bootstrap-multiselect rebuild/refresh not working - bootstrap-multiselect

I have 2 bootstrap-multiselect boxes. I want to refresh the items in one based on the selections made in the other via an Ajax call.
Everything work except that the that the multiselect uses to disoplay the options is not being populated by either 'rebuild' or 'refresh'.
Code:
Decalring the multiselect"
$('#Groups').multiselect({
onChange: function (option, checked) {
//get all of the selected tiems
var values = $('#Groups option:selected');
var selected = "";
$(values).each(function (index, value) {
selected += $(value).prop('value') + ",";
});
selected = selected.substring(0, selected.length - 1);
//update hidden field with comma delimited string for state persistance
$("#Hidden_Groups").val(selected);
},
includeSelectAllOption: true
});
Updating the options list:
$('#JobCodes').multiselect({
onDropdownHide: function(event) {
console.log("start");
var option = $("#Groups");
//clear out old consolidations
option.empty();
console.log("emptied");
////get consolidation and append to select options list
$.getJSON("/Reports/GetGroups/", { options: $("#Hidden_JobCodes").val() }, function (result) {
$.each(result, function (index, item) {
console.log(item.text);
option.append($("<option />").val(item.id).text(item.text));
});
});
option.multiselect('destroy');
option.multiselect('rebuild');
option.multiselect('refresh');
},
Have left the destroy, rebuild and refresh in just as an example things i have tried. Have used all of these in every order and combination and no luck.
Destroy will "change" my multiselect back to a standard select but no matter what I do after that I cannot get the multiselect to come back with the new list of options, including using the full multiselect call wiht the onchange event present. Its either empty of has the old list. The select list has the correct options present when I make the refresh/rebuild calls.
Thanks in advance.
T

Totally my fault!!
The call to /destroy/refresh/rebuild was outside of the ajax call. so the were executing before my new list had been returned, hence no list to rebuild at that time.
Solution:
////get consolidation and append to select options list
$.getJSON("/Reports/GetGroups/", { options: $("#Hidden_JobCodes").val() }, function (result) {
$.each(result, function (index, item) {
console.log(item.text);
option.append($("<option />").val(item.id).text(item.text));
});
option.multiselect('rebuild')
});

Related

jqgrid reload grid on cell edit only for a specific cell

afterSaveCell: function () { $(this).trigger('reloadGrid');},
If I put this in my grid it works well, reloads the grid after a cell edit. Is there an easy or known way to reload only on a specific cell ? something like
//afterSaveCell: function () {
If(the field is budgetyear1){
$(this).trigger('reloadGrid');}
},
First of all you should always place the call of trigger('reloadGrid') inside of setTimeout. It's important because trigger('reloadGrid') works synchronously and the next line after trigger('reloadGrid') will be executed only after reload is finished. If you reload the data from the server, then it's not so critical, but some internal parameters of jqGrid can be already reset (the page number for example).
About you main question: afterSaveCell will be called with 5 parameters: rowid, columnName, cellValue, iRow, iCol. It gives you enough information about the clicked cell and you can use getCell method to get information about any other columns of the row. Thus your could be about the following:
afterSaveCell: function (rowid, columnName, cellValue, iRow, iCol) {
var $self = $(this); // cache this to be used later in `setTimeout`
if (/*test some conditions*/) {
setTimeout(function() {
$self.trigger("reloadGrid");
}, 50);
}
}

jqGrid row selected but not highlighted

I want to select and unselect a row multiple times by clicking.
My code is so far: (lastSelected is a global var):
beforeSelectRow: function (id)
{
if (lastSelected !== id)
{
grid.setSelection(id);
lastSelected = id;
return;
}
else
{
grid.resetSelection(id);
lastSelected = null;
}
}
The code works fine, but row is highlighted only after first click. The Second click unhighlight it and it keep being unhighlighted when I click it next times, but after 3rd, 5th... clicks it behave like selected (I have modal which pops up when row is selected), but is not highlighted.
Without grid.getSelection(id) it won't highlight at all, but still working like it was selecting and deselecting.
It seems to me that the main error in your code is the returned value of beforeSelectRow. If the returned value in not false then the standard processing will be continued and the row which you previously selected explicitly by usage setSelection can be unselected.
To fix the problem you should return false from beforeSelectRow. Additionally I would suggest to use $(this) instead of grid variable and to use standard selrow parameter of jqGrid instead of usage lastSelected variable. The resulting code could be the following
beforeSelectRow: function (rowid, e) {
var $self = $(this), selectedRowid = $self.jqGrid("getGridParam", "selrow");
if (selectedRowid === rowid) {
$self.jqGrid("resetSelection");
} else {
$self.jqGrid("setSelection", rowid, true, e);
}
return false; // don't process the standard selection
}
The corresponding demo is here.

Kendo Grid: Keep custom popup open after save new record

I've got a custom popup editor template for my Kendo Grid which contains tabs. One of the tabs is to have a second Kendo Grid of records relating to the record being edited.
I'd like to be able to create a new record and immediately start adding the related records, without having to re-open the newly created record. Obviously, I have to first save the record in order for its ID to be generated.
I've managed to prevent the popup editor closing when new records are saved, but I think the popup window is no longer bound to the model at this point.
Is there a way I can rebind the window to the model so I can carry on editing and adding the related records?
Thanks
Edit: Here's the technique for keeping the editor open:
The grid's edit and save events:
edit: function(e){
var editWindow = this.editable.element.data("kendoWindow");
editWindow.bind("close", onWindowEditClose);
},
save: function(e){
if (e.model.isNew()) {
preventCloseOnSave = true;
} else {
preventCloseOnSave = false;
}
}
The onWindowEditClose:
var onWindowEditClose = function(e) {'
if (preventCloseOnSave) {
e.preventDefault();
preventCloseOnSave = false;
}
};
I ended up using a slightly clunky workaround, but other than a minor UI 'flash' it works okay.
The Grid has a rowTemplate, so I've added the record's ID field to the TR tags so I can find them by ID. I then have a function that runs on the complete event when a new record is created which finds the new row and immediately opens it:
var ds = new kendo.data.DataSource({
// ...
transport: {
create: {
url: '/url/to/create',
dataType: 'json',
type: 'post',
complete: recordCreated
}
});
function recordCreated(e) {
"use strict";
var id = e.responseJSON.data[0].id,
grid = $('#grid').data("kendoGrid"),
row = grid.tbody.find("tr[data-id='" + id + "']");
grid.editRow(row);
}
On a conceptual level, you could intercept the POST action that saves the record to the database and get the saved data on return. Note that your POST action must return the saved object (as is expected). You can hook into this event by using the requestEnd method of the Kendo UI Datasource object that supports your grid and bind the saved record to your edit window (as long as you have a reference to it).
var ds = new kendo.data.DataSource({
// ...
requestEnd: function (e) {
kendo.bind(editWindow, e.response); // bind the returned data to your edit window
}
});
The understanding of the kendo ui structure (which can be tedious at times) is important to getting anything done with it. The closing of the popup that allows inserting is done in the dataBinding event. Therefore, that is the place we need to prevent it from:
$("#yourgrid").kendoGrid({
dataSource: yourDataSource,
columns: [
{ field: "YouColumn", title: "YourTitle", ... },
...
]
.
.
.
editable: "popup",
dataBinding: function(e){
//this is the key to keeping the popup open
e.preventDefault();
},
save: function (e) {
//whatever you need to do here
}
.
.
.
});
Hope this helps someone.
//Houdini

Kendo AutoComplete - force users to make valid selection

I've got a few Kendo AutoComplete fields linked to remote data (hundreds of possibilities, so DropDownList is not an option).
How can I force users to make a selection from the displayed list?
I'm also retrieving the additional data that's returned from the data source, e.g.
$("#station").kendoAutoComplete({
dataSource: stationData,
minLength: 2,
dataTextField: 'name',
select: function(e){
var dataItem = this.dataItem(e.item.index());
console.dir(dataItem);
}
});
I'm doing additional stuff with the data in dataItem and it needs to be a valid selection.
Thanks
SOLVED:
I think I was possibly over-complicating things. The answer is pretty simple and is posted below.
var valid;
$("#staton").kendoAutoComplete({
minLength: 2,
dataTextField: "name",
open: function(e) {
valid = false;
},
select: function(e){
valid = true;
},
close: function(e){
// if no valid selection - clear input
if (!valid) this.value('');
},
dataSource: datasource
});
This method allows users to type whatever they like into the AutoComplete if list not opens. There are two corrections to fix this:
initialize variable valid as false:
var valid = false;
Check if no valid selection in change event, but not in close:
...
change: function(e){ if (!valid) this.value(''); }
The answer the OP posted, in addition to the answer suggested by #Rock'n'muse are definitely good propositions, but both miss an important and desired functional aspect.
When utilizing the solution given by #Mat and implementing the change-vice-close suggestion from #Rock'n'muse, the typed-in value indeed clears from the widget if no selection is made from the filtered data source. This is great; however, if the user types in something valid and selects a value from the filtered list, then places the cursor at the end of the value and types something which now invalidates the value (doesn't return any valid selections from the data source), the typed-in value is not cleared from the widget.
What's happening is that the isValid value remains true if the previously typed-in (and valid) value should be altered. The solution to this is to set isValid to false as soon as the filtering event is triggered. When the user changes the typed-in value, the widget attempts to filter the data source in search of the typed-in value. Setting isValid to false as soon as the filter event is triggered ensures a "clean slate" for the change event as suggested by the solution from #Rock'n'muse.
Because we're setting isValid to false as soon as the filtering event is triggered, we do not need to do so in the open event (as data source filtering must occur before the user will ever see an option to select). Because of this, the open event binding was removed from #Mat's solution. This also means the initial assignment of false upon declaration of isValid is superfluous, but variable assignment upon declaration is always a good idea.
Below is the solution from #Mat along with the suggestions from #Rock'n'muse and with the filtering implementation applied:
var isValid = false;
$("#staton").kendoAutoComplete({
minLength: 2,
dataTextField: "name",
select: function () {
valid = true;
},
change: function (e) {
// if no valid selection - clear input
if (!valid) {
e.sender.value("");
}
},
filtering: function () {
valid = false;
},
dataSource: datasource
});
As an addendum, using the select event binding to set and evaluate a simple boolean value as #Mat proposes is much cleaner, simpler and faster than using a jQuery $.each(...) on the data source in order to make sure the typed-in value matches an actual item of the data source within the change event. This was my first thought at working a solution before I found the solution from #Mat (this page) and such is my reasoning for up-voting his solution and his question.
Perhaps, can you make your own validation by using the blur event :
$("#station").blur(function() {
var data = stationData,
nbData = data.length,
found = false;
for(var iData = 0; iData < nbData; iData++) {
if(this.value === data[iData].yourfieldname) // replace "yourfieldname" by the corresponding one if needed
found = true;
}
console.log(found);
});
You can check this fiddle.
You most likely need some custom logic which to intercept each key stroke after the min length of two symbols is surpassed, and prevent the option to enter a character which makes the user string not match any of the items from the autocomplete list.
For this purpose intercept the change event of the Kendo autocomplete and compare the current input value from the user against the items from the filtered list.
Hope this helps,
$("#autocomplete_id").val("");
$("#autocomplete").kendoAutoComplete({
dataSource: datasource,
minLength: 1,
dataTextField: "catname",
dataValueField:"id",
select: function(e) {
var dataItem = this.dataItem(e.item.index());
$("#autocomplete_id").val(dataItem.id);
},
dataBound: function(e){
$("#autocomplete_id").val("");
}
});
FYI, autocomplete_id is a hidden field to store the value of the autocomplete. - Sometimes, we would like to have the dataValueField other than dataTextField. So, it serves its purpose.
In this you can get the value of the autocomplete "id" from the element autocomplete_id - which is dataValueField from serverside.
In databound, its values is set to null, and on select, it is assigned the "id" value.
Although the accepted answer works, it is not the best solution.
The solution provided doesn't take into account if the user enters a value before even the kendo AutoComplete widget triggers the open event. In result, the value entered is not forced and therefore, the entry/selection is invalid.
My approach assumes that the application is running in MVC and the array is passed in ViewData. But this can be changed to suit your environment.
My approach:
var validSelect, isSelected;
$("#staton").kendoAutoComplete({
minLength: 2,
filter: "startswith",
dataTextField: "name",
filtering: function(e) {
validSelect = false;
dataArr = #Html.Raw(Json.Encode(ViewData["allStatons"]));
// for loop within the ViewData array to find for matching ID
for (var i = 0; i < dataArr .length; i++){
if (dataArr[i].ID.toString().match("^" + $("#staton").val())) {
validSelect = true;
break;
}
}
// if value entered was not found in array - clear input
if (!validSelect) $("#staton").val("");
},
select: function(e){
isSelected = true;
},
close: function(e){
// if selection is invalid or not selected from the list - clear input
if (!validSelect || !isSelected) $("#staton").val("");
},
dataSource: datasource
});
As you can see, this approach requires the array from the server side on load so that it can match during the filtering event of the widget.
I found this on Telerik's site by just using the change event. For me this works best. I added the "value === ''" check. This will catch when the user "clears" the selection.
Here's the link to the full article.
$("#countries").kendoAutoComplete({
dataSource: data,
filter: "startswith",
placeholder: "Select country...",
change: function() {
var value = this.value();
if (value === '') return;
var found = false;
var data = this.dataSource.view();
for(var idx = 0, length = data.length; idx < length; idx++) {
if (data[idx] === value) {
found = true;
break;
}
}
if (!found) {
this.value("");
alert("Custom values are not allowed");
}
}
});
In my AutoComplete Change event I check for a selected item and clear the cell if not selected.
function myAutoComplete_OnChange(e)
{
if (this.dataItem())
{
// Don't use filtered value as display, instead use this value.
e.sender.element[0].value = this.dataItem().WidgetNumber;
}
else
{
var grid = $("#grid").data("kendoGrid");
grid.dataItems()[grid.select().index()].WidgetKey = null;
grid.dataItems()[grid.select().index()].WidgetNumber = null;
}
}

Using jQGrid and jQUery tabs how to oprimize the number of grids

I have 3 different tabs where i am displaying data using jQGrids(each tab contain one grid).
But i just thought that my grids are completely the same, only the difference is that they using different url to get data.
So I have three similar girds on each tab only with different urls:
First: url: '/Home/GetData?id=1' Second: url: '/Home/GetData?id=2' and Third: url: '/Home/GetData?id=3'
So i was thinking that may be i may declare grid only once and than on each tab click a can pass the url to load data? So on each tab click jQGrid will be populating from the new url.
May be some one may have any ideas about that?
Or may be some one may have better ideas how to reduce "jQGrid copy-paste" in that case?
UPDATE 0:
Nearly get it work i mean it is working but there is one small problem,
When i am switching tabs the header of the grid getting lost...and some jqgrid formatting as well.
here is my code:
$("#tabs").tabs({
show: function (event, ui) {
if (ui.index == 0) {
//$("#Grid1").appendTo("#tab1");
//$("#Grid1Pager").appendTo("#tab1");
//When Appending only pager and grid div, header getting lost so i've append the whole grid html instead
$("#gbox_Grid1").appendTo("#tab1");
changeGrid("#Grid1", 1);
}
else if (ui.index == 1) {
//$("#Grid1").appendTo("#tab2");
//$("#Grid1Pager").appendTo("#tab2");
$("#gbox_Grid1").appendTo("#tab2");
changeGrid("#Grid1", 2);
}
else if (ui.index == 2) {
//$("#Grid1").appendTo("#tab3");
//$("#Grid1Pager").appendTo("#tab3");
$("#gbox_Grid1").appendTo("#tab3");
changeGrid("#Grid1", 3);
}
}
});
function changeGrid(grid, id) {
$(grid).jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id
});
$(grid).trigger('reloadGrid');
}
UPDATE 1
All right, i've changed the code to append the whole grid instead of appending grid div and pager only. So it is working like that.
You can basically make the tabs as regular buttons that will call some function which sets new URL parameter to the grid and reloads it.
The function should be something like this:
function changeGrid(grid, id) {
$(grid).jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id, page: 1
});
$(grid).trigger('reloadGrid');
}
Note that I set the page to 1. Keep in mind that you might need to set the default sorting column or something similar depending on your solution.
UPDATE
If you really want to go with the tabs, the 'show' event handler can be simplified.
Try this:
$("#tabs").tabs({
show: function (event, ui) {
var id = ui.index + 1;
$("#gbox_Grid1").appendTo("#tab" + id);
$("#Grid1").jqGrid('setGridParam', {
url: '/Home/GetData?id=' + id
});
$("#Grid1").trigger('reloadGrid');
}
});

Resources