ExtJS : move a record in a grid - grid

I have a simple grid on ExtJS and would like the user to be able to move the record from its original position.
When the user double clicks on a record, a small window containing a combobox appears, he can choose a value on the combobox and then click the save button to apply the change.
However, it doesn't work, I've searched many solutions for this on different forums and none seems to work. Either nothing happens, or an undefined row is added at the end of the grid. Here is the base code I use :
onEditRank: function(view, cell, cellIndex, record, row, rowIndex, e)
{
var reditor = Ext.create('CMS.view.Views.RankEditor', {id: 'reditorView'});
var form = reditor.down('form');
var oldPos = this.getFlatrq().getView().indexOf(record);
var grStore = this.getGridRnkStoreStore();
var i;
var data = [];
for(i = 1; i <= CMS.global.Variables.limit + 1; i++)
{
data.push(i);
}
var combo = Ext.create
(
'Ext.form.field.ComboBox',
{
fieldLabel: 'Rank',
itemId: 'cmbRank',
store: data
}
);
var saveRnk = Ext.create
(
'Ext.button.Button',
{
text: 'Save',
handler: function()
{
}
}
);
form.add(combo);
form.add(saveRnk);
reditor.show();
}
Now here are the different handlers I have tried for my save button :
handler: function()
{
grStore.remove(record);
grStore.insert(record, combo.getValue() - 1);
this.up('form').up('window').close();
}
handler: function()
{
grStore.removeAt(oldPos);
grStore.insert(record, combo.getValue() - 1);
this.up('form').up('window').close();
}
handler: function()
{
var rec = grStore.getAt(oldPos).copy();
grStore.removeAt(oldPos);
grStore.insert(rec, combo.getValue() - 1);
this.up('form').up('window').close();
}
Those 3 handlers inserted undefined rows at the end of my grid. I displayed the values of oldPos and combo.getValue() and they are correct, I also displayed the record variable before and after the remove because I thought it might be destroyed but it wasn't. I have also tried to add a move function to store and call it :
'CMS.store.GridRnkStore',
{
extend: 'Ext.data.Store',
model: 'CMS.model.GridRnkModel',
autoLoad: false,
filterOnLoad: true,
autoSync: true,
move: function(from, to)
{
console.log(from + " " + to);
var r = this.getAt(from);
this.data.removeAt(from);
this.data.insert(to, r);
this.fireEvent("move", this, from, to);
},
}
);
But it didn't work either, it did nothing actually (I put some console.log in the move function to see if it was called and it was, with the right parameters). I'm running out of ideas, any help would be appreciated.
Thank you.

try to set the private move parameter to true of store.remove():
remove: function(records, /* private */ isMove, silent)

Related

Fullcalendar using resources as a function with select menu

Using Fullcalendar 4, I am trying to show/hide my resources using a select menu. When the user selects one of the providers from a menu, I want to only show that one resourc's events.
Above my fullcalendar I have my select menu:
<select id="toggle_providers_calendar" class="form-control" >
<option value="1" selected>Screech Powers</option>
<option value="2">Slater</option>
</select>
I am gathering the resources I need using an ajax call on my included fullcalendar.php page. I am storing them in an object and then trying to control which resources are shown onscreen:
document.addEventListener('DOMContentLoaded', function() {
var resourceData = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
console.log(resourceData);
});
//below, set the visible resources to whatever is selected in the menu
//using 1 in order for that to show at start
var visibleResourceIds = ["1"];
//below, get the selected id when the the menu is changed and use that in the toggle resource function
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
var calendar_full = document.getElementById('calendar_full');
var calendar = new FullCalendar.Calendar(calendar_full, {
events: {
url: 'ajax_get_json.php?what=location_appointments'
},
height: 700,
resources: function(fetchInfo, successCallback, failureCallback) {
// below, I am trying to filter resources by whether their id is in visibleResourceIds.
var filteredResources = [];
filteredResources = resourceData.filter(function(x) {
return visibleResourceIds.indexOf(x.id) !== -1;
});
successCallback(filteredResources);
},
...
});
// below, my toggle_providers_calendar will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
To make sure the getJSON is working, I have console.log(resourceData). The information in the console once it's gathered is:
[{id: '1', title: 'Screech Powers'}, {id: '2', title: 'Slater}]
... the above are the correct resources that can be chosen/rendered. So that seems to be okay.
On page load, no resources show at all, when resource id of '1' (Screech Powers) should be shown per my code. Well, at least, that's what I am trying to do right now.
When the menu changes, resources will show/hide, but not based on what's selected; the logic of only showing what is selected in the menu doesn't seem to be working.
I used to use a URL request for my resources: 'ajax_get_json.php?what=schedule_providers_at_location', and it worked fine! All resources show then their events properly. I am just trying to modify it by using a menu to show/hide the resources as needed.
Here's what I'm doing to make it happen so far! In case someone comes across this post ever, this will help.
Here's my code before my fullcalendar code.
var resourceData = [];
var visibleResourceIds = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
});
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
My select menu with id 'toggle_providers_calendar' is the same as my original post. My fullcalendar resources as a function is the same too.
After the calendar is rendered, here are the changes I made to my toggle resources function:
// menu button/dropdown will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
visibleResourceIds = [];
//if select all... see if undefined from loading on initial load = true
if ((resourceId == '') || (resourceId === undefined)) {
$.map( resourceData, function( value, index ) {
visibleResourceIds.push(value.id);
});
}
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
This causes the resources to show and hide properly. If the user selects "Show All" that works too!
In order to have a default resource show on load, I add this to my fullcalendar script:
loading: function(bool) {
if (bool) {
//insert code if still loading
$('.loader').show();
} else {
$('.loader').hide();
if (initial_load) {
initial_load = false;
//code here once done loading and initial_load = true
var default_resource_to_show = "<?php echo $default_provider; ?>";
if (default_resource_to_show) {
//set the menu to that provider and trigger the change event to toggleresrource()
$('#toggle_providers_calendar').val(default_provider).change();
} else {
//pass in nothing meaning 'select all' providers for scheduler to see
toggleResource();
}
}
}
},
I am using a bool variable of initial_load to see if the page was just loaded (basically not loading data without a page refresh). The bool of initial_load = true is set outside of DOMContentLoaded
<script>
//show selected date in title box
var initial_load = true;
document.addEventListener('DOMContentLoaded', function() {
My only current problem is that when toggleResource function is called, the all day vertical time block boundaries don't line up with the rest of the scheduler. Once I start navigating, they do, but I don't understand why it looks like this on initial load or when toggleResource() is called:
Any thoughts on how to correct the alignment of the allday vertical blocks?

Dynamically toggle resource column visibility

I have a FullCalendar scheduler on a webapp which has 2 way databinding for resources and events, all working great. I want to be able to present the user with a dropdown that enables them to toggle the visibility of a column, ideally completely client side.
I have tried a combination of addResource / removeResource however my issue here is that a rerender of the calendar (e.g. when a new event is added) then displays the previously removed resource. I can work around this however would prefer a really simple approach using JS / CSS. I currently cannot find a way to set a resource to not be visible, or to have zero width - is this possible?
There is an easy way to do this:
Store resources in an array variable resourceData.
Create another array called visibleResourceIds to store the ids of any resources you want to show.
In the resources callback function, filter resourceData to only contain the resources where the resource id exists in visibleResourceIds. Return the filtered array and fullcalendar will only add the desired resources for you.
To remove a resource from view, simply remove the resource id from visibleResourceIds and refetchResources. To add the resource back in, add the id to visibleResourceIds and refetchResources. DONE.
JSFiddle
var resourceData = [
{id: "1", title: "R1"},
{id: "2", title: "R2"},
{id: "3", title: "R3"}
];
var visibleResourceIds = ["1", "2", "3"];
// Your button/dropdown will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
$('#calendar').fullCalendar('refetchResources');
}
$('#calendar').fullCalendar({
defaultView: 'agendaDay',
resources: function(callback) {
// Filter resources by whether their id is in visibleResourceIds.
var filteredResources = [];
filteredResources = resourceData.filter(function(x) {
return visibleResourceIds.indexOf(x.id) !== -1;
});
callback(filteredResources);
}
});
I had the same challenge. Instead of a dropdown, I use checkboxes, but the workings will be the same.
My resources are stored in a variable, when I uncheck a box, the resource is removed and the resource's object is added to another array with the resourceId as key, and the index added to the object to restore the object in the same column as it originally was. When re-checking the box, the object is added to the resources array and the resources refetched.
/* retrieve the resources from the server */
var planningResources;
var removedResource = [];
$.ajax({
url: '/planning/resources/',
method: 'get',
success: function (response) {
planningResources = response;
showCalendar();
}
, error: function () {
if (typeof console == "object") {
console.log(xhr.status + "," + xhr.responseText + "," + textStatus + "," + error);
}
}
});
/* create the calendar */
showCalendar = function () {
$('#calendar').fullCalendar({
...
});
}
/* checkbox on click */
$('.resource').click(function() {
var resourceId = $(this).val();
var hideResource = !$(this)[0].checked;
$('.status:checkbox:checked').each(function () {
});
if(hideResource) {
$.each(planningResources, function(index, value){
if( value && value.id == resourceId ) {
value.ndx = index;
removedResource[resourceId] = value;
planningResources.splice(index,1);
return false;
}
});
$('#planningoverview').fullCalendar(
'removeResource',
resourceId
);
}
else {
planningResources.splice(removedResource[resourceId].ndx, 0, removedResource[resourceId]);
$('#planningoverview').fullCalendar('refetchResources');
}
});
showCalendar();
It probably doesn't get first price in a beauty contest, but it works for me ...
Cheers
You can use the resourceColumns option for this. In the column objects you can set the width property to a number of pixels or a percentage. If you pass a function here you can easily handle the width property someplace else. Your hide/show function can then set the width to 0 to hide the column. After that you can trigger reinitView to update the view: $('#calendar').fullCalendar("reinitView");

Reactive cursor without updating UI for added record

I am trying to make a newsfeed similar to twitter, where new records are not added to the UI (a button appears with new records count), but updates, change reactively the UI.
I have a collection called NewsItems and I a use a basic reactive cursor (NewsItems.find({})) for my feed. UI is a Blaze template with a each loop.
Subscription is done on a route level (iron router).
Any idea how to implement this kind of behavior using meteor reactivity ?
Thanks,
The trick is to have one more attribute on the NewsItem Collection Say show which is a boolean. NewsItem should have default value of show as false
The Each Loop Should display only Feeds with show == true and button should show the count of all the items with show == false
On Button click update all the elements in the Collection with show == false to show = true
this will make sure that all your feeds are shown .
As and when a new feed comes the Button count will also increase reactively .
Hope this Helps
The idea is to update the local collection (yourCollectionArticles._collection): all articles are {show: false} by default except the first data list (in order not to have a white page).
You detect first collection load using :
Meteor.subscribe("articles", {
onReady: function () {
articlesReady = true;
}
});
Then you observe new added data using
newsItems = NewsItems.find({})
newsItems.observeChanges({
addedBefore: (id, article, before)=> {
if (articlesReady) {
article.show = false;
NewsItems._collection.update({_id: id}, article);
}
else {
article.show = true;
NewsItems._collection.update({_id: id}, article);
}
}
});
Here is a working example: https://gist.github.com/mounibec/9bc90953eb9f3e04a2b3.
Finally I managed it using a session variable for the current date /time:
Template.newsFeed.onCreated(function () {
var tpl = this;
tpl.loaded = new ReactiveVar(0);
tpl.limit = new ReactiveVar(30);
Session.set('newsfeedTime', new Date());
tpl.autorun(function () {
var limit = tpl.limit.get();
var time = Session.get('newsfeedTime');
var subscription = tpl.subscribe('lazyload-newsfeed', time, limit);
var subscriptionCount = tpl.subscribe('news-count', time);
if (subscription.ready()) {
tpl.loaded.set(limit);
}
});
tpl.news = function() {
return NewsItems.find({creationTime: {$lt: Session.get('newsfeedTime')}},
{sort: {relevancy: -1 }},
{limit: tpl.loaded.get()});
},
tpl.countRecent = function() {
return Counts.get('recentCount');
},
tpl.displayCount = function() {
return Counts.get('displayCount');
}
});
Template.newsFeed.events({
'click .load-new': function (evt, tpl) {
evt.preventDefault();
var time = new Date();
var limit = tpl.limit.get();
var countNewsToAdd = tpl.countRecent();
limit += countNewsToAdd;
tpl.limit.set(limit);
Session.set('newsfeedTime', new Date());
}
});

How to return number of items in collection?

I'm new to Meteor and I want to create a slideshow with items from a collection, in this case simple words. The slideshow should be controlled by back and forward buttons and replace the current word.
In JavaScript/jQuery I would create an array of objects and a control index, with limits via if-statements, so the index never can drop below zero or overflow the length of the array.
See fiddle for working example:
http://jsfiddle.net/j0pqd26w/8/
$(document).ready(function() {
var wordArray = ["hello", "yes", "no", "maybe"];
var arrayIndex = 0;
$('#word').html(wordArray[arrayIndex]);
$("#previous").click(function(){
if (arrayIndex > 0) {
arrayIndex -= 1;
}
$('#word').html(wordArray[arrayIndex]);
});
$("#next").click(function(){
if (arrayIndex < wordArray.length) {
arrayIndex += 1;
}
$('#word').html(wordArray[arrayIndex]);
});
});
Meteor
I'm curious how to implement this in regards to best practice in meteor and abide to the reactive pattern as I'm still trying to wrap my head around this interesting framework. My first hurdle is to translate the
if (arrayIndex < wordArray.length)
// to
if (Session.get("wordIndex") < ( (((length of collection))) )
According to the docs I should do a find on the collection, but I have only manage to return an empty array later with fetch. Sorry if this got long, but any input would be appreciated to help me figure this out.
collection.find([selector], [options])
cursor.fetch()
This is the code I have so far:
Words = new Mongo.Collection("words");
if (Meteor.isClient) {
// word index starts at 0
Session.setDefault("wordIndex", 0);
Template.body.helpers({
words: function () {
return Words.find({});
},
wordIndex: function () {
return Session.get("wordIndex");
}
});
Template.body.events({
"submit .new-word": function (event) {
// This function is called when the word form is submitted
var text = event.target.text.value;
Words.insert({
text: text,
createdAt: new Date() //current time
});
// Clear form
event.target.text.value = "";
// Prevent default form submit
return false;
},
'click #previous': function () {
// decrement the word index when button is clicked
if (Session.get("wordIndex") > 0) {
Session.set("wordIndex", Session.get("wordIndex") - 1);
}
},
'click #next': function () {
// increment the word index when button is clicked
if (Session.get("wordIndex") < 10 ) {
Session.set("wordIndex", Session.get("wordIndex") + 1);
}
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
});
}
.count() will return the number of documents in a collection.
`db.collection.count()`
There is something called Collection helpers, which works similar to other helpers (eg., template, etc.,). More elaborate explanation is covered here: https://medium.com/space-camp/meteor-doesnt-need-an-orm-2ed0edc51bc5

Unique Dropdownlist is coming for the first page values in Jqgrid

Hello Every One!!!
I added codes for getting unique dropdownlist in the columns of jqgrid .
Dropdownlist is coming but it is coming for the first page of the jqgrid means that dropdownlist has the unique values of the first page of the jqgrid whereas i need all the unique values of the whole Jqgrid..
Below I am posting my codes...
grid = $("#gridId");
getUniqueNames = function (columnName) {
var texts = grid.jqGrid('getCol', columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i = 0; i < textsLength; i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
},
buildSearchSelect = function (uniqueNames) {
var values = ":All";
$.each(uniqueNames, function () {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function (columnName) {
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value: buildSearchSelect(getUniqueNames(columnName)),
sopt: ['eq']
}
}
);
};
This function i have called like this...
setSearchSelect('extension');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt: ['cn'],
dataInit: function (elem) {
$(elem).autocomplete({
source: getUniqueNames('Name'),
delay: 0,
minLength: 0
});
}
}
});
setSearchSelect('username');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt: ['cn'],
dataInit: function (elem) {
$(elem).autocomplete({
source: getUniqueNames('Name'),
delay: 0,
minLength: 0
});
}
}
});
In between these two code snippets I am loading data into jqgrid locally using Ajax call.
Any help will be heartely appreciated..
Thanx in advance..
I belive getCol will return only currently loaded data from jqgrid (for defined column).
Because at first you load just first page, autocomplete has no way of knowing unique values of column for more than that!
You will have to either load all pages at once (small dataset) or
fill autocomplete from database.

Resources