Jqgrid - Multiselectected rows no longer persist after triggering a JqGrid reload - asp.net-mvc-3

I have a multi-selected Jqgrid. Initially on loading the grid with the Json reponse from the server, the multiselected rows persist correctly as I navigate from one page to another.
The ids of the rows selected are stored in an Array and this Array is updated on paging. I use this array to check the already selected rows on returning back to the page. Sorting works fine and I faced no problem so far.
On applying a filter on a particular field, a request is sent to the server which returns the new filtered result in Json and then reloads the grid with it.
The first page is rendered correctly with the selected rows checked but on changing the page and returning back the rows are no longer selected. However the array still contains the ids and is also containing the new added ids.
How is that the Multiselected feature stops working after a reload??? Or is it not even because of the reload??
Here is the code:
<script type='text/javascript'>
var selectedFieldsMap={};
var selectedFieldsObjs = [];
var selectedFieldIds = [];
$(function() {
//function called when applying a filter
$('#ApplyFilterBtn').click(function() {
saveGridState();
$('#Grid').setGridParam({ url: getUrl() });
$('#Grid').trigger('reloadGrid');
});
});
function saveGridState() {
var selectedIds = $('#Grid').getGridParam('selarrrow');
$('#Grid').data(current_page, selectedIds);
_.each(selectedIds, function(id) {
selectedFieldIds.push(id);
});
var idsToBeAdded = _.difference(selectedIds, getExistingRowIdsForGrid('#list'));
selectedFieldsMap[current_page] = idsToBeAdded;
_.each(idsToBeAdded, function(id) {
selectedFieldsObjs.push($('#Grid').getRowData(id));
});
}
function getExistingRowIdsForGrid(gridSelector) {
var existingFields = $(gridSelector).getRowData();
return _.map(existingFields, function(obj) { return obj.Id; });
function resetFilterValuesAndReloadGrid() {
//reset filters and set grid param
$('#Grid').setGridParam({
sortname: 'Id',
sortorder: 'asc',
page: 1,
url: getUrl()
});
$('#Grid').jqGrid('sortGrid', 'Id', true);
$("#Grid").trigger('reloadGrid');
}
$("#Grid").jqGrid({
url: getUrl(),
datatype: "json",
edit: false,
add: false,
del: false,
height: 330,
mtype: 'GET',
colNames: ['Id', 'Type', 'Category'],
jsonReader: {
root: "DataRoot",
page: "CurrentPage",
total: "TotalPages",
records: "TotalRecords",
repeatitems: false,
cell: "",
id: "0"
},
colModel: [
{ name: 'Id', index: 'Id', width: 95, align: 'center', sorttype: "int" },
{ name: 'Type', index: 'ValueTypeName', width: 110, align: 'left',sortable: true },
{ name: 'Category', index: 'Category', width: 72, align: 'left', sortable: true },
],
pager: '#pager',
rowNum: pageCount[0],
rowList: pageCount,
sortname: 'Id',
sortorder: 'asc',
viewrecords: true,
gridview: true,
multiselect: true,
loadComplete: function () {
if(selectedFieldIds) {
$.each(_.uniq(selectedFieldIds), function(index, value) {
$('#Grid').setSelection(value, true);
});
}
} ,
onPaging : function () {
saveGridState();
},
loadBeforeSend: function() {
current_page = $(this).getGridParam('page').toString();
} ,
onSortCol: function () {
saveGridState();
}
});
}
function getUrl() {
//return url with the parameters and filtering
}
</script>

The problem is solved, what happens is on reload of the grid the function which checks the row is called as it is in the document.ready()and the on grid loadComplete the same function is called. Toggle happens and the selection is removed. I've added an if condition to see if the grid is selected or not.
loadComplete: function () {
var selRowIds = jQuery('#Grid').jqGrid('getGridParam', 'selarrrow');
if (selRowIds.length > 0) {
return false;
} else {
var $this = $(this), i, count;
for (i = 0, count = idsOfSelectedRows.length; i < count; i++) {
$this.jqGrid('setSelection', idsOfSelectedRows[i], false);
}
}
}

Related

JQGrid MultiSelect Filter option populate based on column's distinct value

I am using JQGrid with Multiselect filter to filter individual columns.
Currently I am populating filters(e.g. SkillCategory column) using database master values
{
name: 'SkillCategory', index: 'SkillCategory', width: '5%', sortable: true, resizable: true, stype: 'select',
searchoptions: {
clearSearch: false,
sopt: ['eq', 'ne'],
dataUrl: 'HttpHandler/DemandPropertyHandler.ashx?demprop=skillcat',
buildSelect: createSelectList,
attr: { multiple: 'multiple', size: 4 },
position: {
my: 'left top',
at: 'left bottom'
},
dataInit: dataInitMultiselect
}
},
This approach is populating all available master list(for SkillCategory) in to filter.
I would like to show only available filter value based on those are present in available rows for particular column(for SkillCategory).
This should show "Programming" and "Data" as option for SkillCategory filter as rows contains only "Programming" and "Data" value for that column.
I found below code(sorry forgot the link)
getUniqueNames = function (columnName) {
var texts = $("#listTableSupply").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) {
$("#listTableSupply").jqGrid('setColProp', columnName,
{
searchoptions: {
sopt: ['eq', 'ne'],
value: buildSearchSelect(getUniqueNames(columnName)),
attr: { multiple: 'multiple', size: 3 },
dataInit: dataInitMultiselect
}
}
);
}
Calling setSearchSelect("SkillCategory")
.... caption: 'Supply',
emptyrecords: "No records to view",
loadtext: "Loading...",
refreshtext: "Refresh",
refreshtitle: "Reload Grid",
loadComplete: loadCompleteHandler1,
ondblClickRow: function (rowid) {
jQuery(this).jqGrid('viewGridRow', rowid);
},
beforeRequest: function () //loads the jqgrids state from before save
{
modifySearchingFilter.call(this, ',');
}
}).jqGrid('bindKeys');
$('#listTableSupply').bind('keydown', function (e) {
if (e.keyCode == 38 || e.keyCode == 40) e.preventDefault();
});
setSearchSelect("SkillCategory");
$('#listTableSupply').jqGrid('navGrid', '#pagerSupply', {
cloneToTop: true,
refresh: true, refreshtext: "Refresh", edit: false, add: false, del: false, search: false
}, {}, {}, {}, {
multipleSearch: true,
multipleGroup: true,
recreateFilter: true
}); .....
But seems its not working. Only "All" value is populated.
Any idea how can I achieve this.
Update1:
As per Oleg's suggestion below is the working code which worked for me.
initializeGridFilterValue = function () {
//jQuery("#listTableSupply").jqGrid('destroyGroupHeader');
setSearchSelect("SkillCategory");
jQuery("#listTableSupply").jqGrid("filterToolbar", {
stringResult: true,
searchOnEnter: true,
defaultSearch: myDefaultSearch,
beforeClear: function () {
$(this.grid.hDiv).find(".ui-search-toolbar .ui-search-input>select[multiple] option").each(function () {
this.selected = false; // unselect all options
});
$(this.grid.hDiv).find(".ui-search-toolbar button.ui-multiselect").each(function () {
$(this).prev("select[multiple]").multiselect("refresh");
}).css({
width: "98%",
marginTop: "1px",
marginBottom: "1px",
paddingTop: "3px"
});
}
});
jQuery("#listTableSupply").jqGrid('setGridHeight', 300);
}
And setting it from loadComplete event like below:
function loadCompleteHandler1() {
initializeGridFilterValue();
}
I see that you use the code from my old answer. About your problem: I suppose that you first call filterToolbar which creates the filter toolbar and only later you call setSearchSelect which set new searchoptions.value property. Another possible problem is that you call setSearchSelect before the data will be loaded in the grid. If you use datatype: "local" with data parameter then the data are filled in the grid during creating of the grid. If you use datatype: "json" then you should first load the data from the server and then call setSearchSelect and filterToolbar inside of loadComplete. For example if you use loadonce: true then you can test the value of datatype parameter inside of loadComplete. If the value is "json" then you made initial loading of the data. So you should call setSearchSelect, then if required call destroyFilterToolbar and finally call filterToolbar to create filter toolbar which selects will have all required values.

Add check boxes in Jquery grid view

I have the following code in page which binds the data to j query grid.
Now i want to add one more column for check-boxes to the existing grid and when i select some check boxes and press some button .. i need to get the selected row values .
I have seen some tutorials for this they mentioned about some formatter .... but they are not clear
Please help me to achieve this.
Thanks in advance.
Code:
$(document).ready(function () {
$("#btn_GenerateEmpList").click(function () {
var firstClick = true;
if (!firstClick) {
$("#EmpTable").trigger("reloadGrid");
}
firstClick = false;
var empId= $("#txt_emp").val();
$.ajax({
type: "POST",
url: "PLBased.aspx/GetEmpNames",
data: JSON.stringify({ empId: empId}),
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function (result) {
result = result.d;
jQuery("#EmpTable").jqGrid({
datatype: "local",
colNames: ['Emp Name'],
colModel: [
{ name: "EmpName", Index: "EmpName", width: 80 }
],
data: JSON.parse(result),
rowNum: 10,
rowList: [5, 10, 20],
pager: '#pager',
loadonce: false,
viewrecords: true,
sortorder: 'asc',
gridview: true,
autowidth: true,
sortname: 'EMPID',
height: 'auto',
altrows: true,
});
},
error: function (result) {
alert("There was some error ");
}
});
});
});
You can use customformatter to show checkbox in the column. For this, you can write the code as below in your jqGrid Code.
colNames: ['Id','Emp Name','Emp Checkbox'],
colModel: [
{ name: 'Id', index: 'Id', hidden: true },
{ name: 'EmpName', Index: 'EmpName', width: 80 },
{ name: 'Empchk', Index: 'Empchk', width: 50, align: 'center', editable: true, edittype: "checkbox", editoptions: { value: "true:false" },
formatter: generateEmpCheckBox, formatoptions: { disabled: false } }
],
formatter function code as below,
function generateEmpCheckBox(cellvalue, options, rowObject) {
var checkedStr = "";
if (cellvalue == true) {
checkedStr = " checked=checked ";
}
return '<input type="checkbox" onchange="UpdateEmpcheckbox(' + rowObject.Id + ',this)" value="' + cellvalue + '" ' + checkedStr + '/>';
}
function UpdateEmpcheckbox(selectedId, chkBox) {
if ($(chkBox).prop("checked")) {
//you can write an ajax here, to update the server
//when the checkbox is checked
}
else if (!($(chkBox).prop("checked"))) {
//you can write an ajax here to update the server
//when the checkbox is unchecked
}
return false;
}
Set the option multiselect:true which will add column of checkboxes. Then add
$('#EmpTable').jqGrid('getGridParam', 'selarrrow')
will return an array of selected id's.

Passing extra parameters in JQGrid delete with multiselect

I want to have delete functionality in my JQGrid for deleting multiple rows. My code looks like this:
{height:180,mtype:"POST",closeAfterDel:true, url:'gridedit.jsp',reloadAfterSubmit:true,
onclickSubmit: function (options, rowid) {
var rowData = jQuery(this).jqGrid('getRowData', rowid);
var params ={amount:rowData.amount,account:rowData.account.replace(/-/g,"")};
return params;
},
afterSubmit: function () {
$(this).jqGrid('setGridParam', {datatype:'json'});
return [true,''];
}
}
I want to make deletions as per the values of the column rowData.account
The problem is that when I select multiple rows, I can see that the grid passes all the rowid's back to the edit URL, but only passes the rowData.account value of the first row !
Is there a way to make the grid pass back all the values? I cant delete based on the row id on the back end as my database does not have any row id's.
Please help.
Here is my grid code:
jQuery(document).ready(function(){
jQuery("#list").jqGrid({
datatype: 'json',
url:'gridfeeder.jsp?ctlSelectedDate=<%= request.getParameter("ctlSelectedDate")%>',
colNames: ['Date', 'Account ', 'Amount', 'Code'],
colModel: [
//First Column, DATE
{name: 'adate', index: 'adate', width: 300, sorttype: 'date', align: 'center',datefmt: 'Y-m-d',
editable:true, formatter: myLinkFormatter, editoptions:{
dataInit:function(elem)
{
jQuery(elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true
});
}}, search:true, stype:'text',searchoptions:{
dataInit:function(elem)
{
jQuery(elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true
});
}
}
},
//Second Column, ACCOUNT
{ name: 'account', index: 'account', width: 300, align: 'center', sorttype: 'string', editable:true,
search:true, stype:'text',editrules:{custom:true, custom_func:
//Validation for this column for editing
function(value, colname) {
if (value.length<9 || value.length>11)
return [false,"Invalid Input"];
else
return [true,""];
}
},
searchrules:{custom:true, custom_func:
//Validation for this column for searching
function(val, colname) {
if (val.length<9 || val.length>11)
return [false,"Invalid Input"];
else
return [true,""];
}
}
},
//Third Column, AMOUNT
{ name: 'amount', index: 'amount', width: 300, align: 'center', sorttype: 'float', editable:true,
editrules:{number:true}, search:true, stype:'text'
},
//Fourth Column, CODE
{ name: 'code', index: 'code', width: 300, align: 'center', sorttype: 'float', editable:true,
search:true, stype:'text'
}
],
pager: "#pager", //Identifying the navigation bar
rowNum: 500, // how many rows to display on page 1
rowList: [500,1000, 2000, 3000,4000], //values for the dropdown which specifies how many rows to show
sortorder: "desc", //the order of sorting by default
viewrecords: true, // displays total number of rows
gridview: true,
autoencode: true,
height:400, //height of the grid
ignoreCase:true,// case insensitive search
multiselect:true, // checkboxes before each row
multiboxonly: true,
loadonce:true, //for client side sorting, searching and pagination
caption:"This is me" // caption for the grid header
here is the navgrid section :
}).navGrid('#pager',{edit:true,add:true,del:true,search:true,refresh:true},
// Options for EDIT
{height:280,mtype: "POST",closeAfterEdit: true,reloadAfterSubmit:true, url:'gridedit.jsp',
recreateForm: true,
//set some properties beofre the dialog box is seen by the user
beforeShowForm: function(form) {
/*$('#adate',form).attr('readonly','readonly');
$('#account',form).attr('readonly','readonly');*/
$('#adate',form).hide();
$('#account',form).hide();
},
// what happens when the user clicks submit. passing extra parameters
onclickSubmit: function (options, postdata) {
var rowid = postdata[this.id + "_id"]; // postdata.list_id
var dataF = jQuery('#list').jqGrid ('getCell', rowid, 'account');
return {account:dataF.replace(/-/g,"")};
},
// changing the datatype
afterSubmit: function () {
$(this).jqGrid("setGridParam", {datatype: 'json'});
return [true,''];
}
},
//ADD options
{height:280,mtype:"POST", closeAfterAdd:true, reloadAfterSubmit:true, url:'gridedit.jsp',
beforeShowForm: function(form) {
/*var cm = jQuery("#list").jqGrid('getColProp','adate');
alert(cm);
cm.editable = false;
$('#adate',form).attr('readonly','readonly');
$('#account',form).attr('readonly','readonly');*/
$('#adate',form).show();
$('#account',form).show();
},
//Change the datatype
afterSubmit: function () {
$(this).jqGrid("setGridParam", {datatype: 'json'});
return [true, ""];
}
},
{height:180,mtype:"POST",closeAfterDel:true, url:'gridedit.jsp',reloadAfterSubmit:true,
/* onclickSubmit: function (options, rowid) {
var rowData = jQuery(this).jqGrid('getRowData', rowid);
var params ={account:rowData.account.replace(/-/g,"")};
return params;
},*/
delData: {
account: function() {
var sel_id = $("#list").jqGrid('getGridParam', 'selrow');
var value = $("#list").jqGrid('getCell', sel_id, 'account');
return value.replace(/-/g,"");
}
},
afterSubmit: function () {
$(this).jqGrid('setGridParam', {datatype:'json'});
return [true,''];
}
}
);
function myLinkFormatter(cellvalue, options, rowObject) {
return "<a href='account094act.jsp?GETDATE=" + cellvalue + "&GETACC=" + rowObject[1] + "'>" + cellvalue + "</a>";
}
jQuery("#refresh_list").click(function(){
jQuery("#list").setGridParam({datatype: 'json'});
jQuery("#list").trigger("reloadGrid");
});
});
One uses mostly unique values which are the best for your situation as rowids. Probably you should consider to use the value from account column as rowid? You don't posted the full code of jqGrid which you you and don't posted JSON/XML data used for filling the grid. So it's difficult to give an exact advice to you.
You can consider to place key: true property in colModel in the definition of the column account. If all values from the column are unique (the values are different in all rows of the grid) then you can use the settings. In the case the rowid (the value of id attribute of <tr> elements of the grid) will be assigned the same as the values from account column.
All editing operation sends id of the editing row. So you will get account sent to the server. In case of multiselect: true jqGrid send comma separated list of rowids. In your case you will get on the server comma separated list of deleted accounts. Probably you can get all other information (like amount), if it's required, based on the account value. If account value are really unique and you have all data on the server that you can get any information which corresponds to account chosen.

validate jqgrid data on the server, callback function

I am using autocomplete in a textbox on my jqgrid. But i should not allow the user to select the same item twice. Because of pagination he wont see all data all times. Is there a way that on sending new row to server check for duplicate data in the server and send a status back to jqgrid maybe poping up an alert sayign "row already exist on table". What would be the bst approach to do this validation and notify the user? thanks.
$("#assessmentproduct").jqGrid({
url: 'orthofixServices.asmx/GetProductList',
colNames: ['id', 'Product Description', 'Commission Rate'],
colModel: [
{ name: 'id', hidden: true },
{ name: 'description', index: 'desc', width: 320, editable: true },
{ name: 'commissionrate', index: 'com', width: 120, editable: true, unformat: percentUnFormatter, formatter: percentFormatter, editrules: { number: true} }
],
serializeRowData: function(data) {
var params = new Object();
params.id = 0;
params.prdid = $("#prdid").val();
params.description = data.description;
params.commissionrate = data.commissionrate;
var result = JSON.stringify({ 'passformvalue': params, 'oper': data.oper, 'id': data.id });
return result;
},
mtype: "POST",
rowNum: 4,
height: 93,
width: 400,
pager: '#assessmentpager',
editurl: "orthofixServices.asmx/ModifyProductList"
});
$("#assessmentproduct").jqGrid('navGrid', '#assessmentpager', { add: false, edit: false, del: true, refresh: false, search: false }, {}, {}, { serializeDelData: function(postData) {
return JSON.stringify({ 'passformvalue': null, 'oper': postData.oper, 'id': postData.id });
}
});
$("#assessmentproduct").jqGrid('inlineNav', '#assessmentpager', { addParams: { position: "last", addRowParams: {
"errorfunc": duplicateRow, "aftersavefunc": function() { var grid = $("#assessmentproduct"); reloadgrid(grid); }
}
}, editParams: { "aftersavefunc": function() { var grid = $("#assessmentproduct"); reloadgrid(grid); } }
});
You should just hold the simple rule: if an error occur on the server (for example because of validation error) the server response should contains some error HTTP status code. In the case error message will be displayed to the user.
The exact error processing and the displayed error message format depends from the editing mode which you use. In case of inline editing I would recommend you to use errorfunc and restoreAfterError parameters of the editRow method. In case of form editing the errorTextFormat callback can be very helpful.

jqGrid Problem Binding Subgrid

I have a jqGrid that is not correctly displaying the subgrid rows. When I load the page, the regular grid rows display fine as well as the plus sign next to each of them, but when I click the plus button to expand them, the "Loading..." message just remains and nothing happens. I don't know if it makes a difference, but I am trying to do it on client side (loadonce: true).
Here is the code for creating the grid:
$("#Grid1").jqGrid({
// setup custom parameter names to pass to server
prmNames: {
search: null,
nd: null,
rows: "numRows",
page: "page",
sort: "sortField",
order: "sortOrder"
},
datatype: function(postdata) {
$(".loading").show(); // make sure we can see loader text
$.ajax({
url: 'WebServices/GetJSONData.asmx/getGridData',
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(postdata),
dataType: "json",
success: function(data, st) {
if (st == "success") {
var grid = $("#Grid1")[0];
grid.addJSONData(JSON.parse(data.d));
//Loadonce doesn't work, have to do its dirty work
$('#Grid1').jqGrid('setGridParam', { datatype: 'local' });
//After rows are loaded, have to manually load subgrid rows
var subgridData = JSON.parse(data.d).subgrid;
var lista = jQuery("#Grid1").getDataIDs();
var rowData;
//Iterate over each row in grid
for (i = 0; i < lista.length; i++) {
//Get current row data
rowData = jQuery("#Grid1").getRowData(lista[i]);
}
}
},
error: function() {
alert("Error with AJAX callback");
}
});
},
// this is what jqGrid is looking for in json callback
jsonReader: {
root: "rows",
page: "page",
total: "totalpages",
records: "totalrecords",
cell: "cell",
id: "id", //index of the column with the PK in it
userdata: "userdata",
repeatitems: true
},
coNames: ['Inv No', 'Amount', 'Store', 'Notes'],
colModel: [
{ name: 'InvNum', index: 'InvNum', width: 200 },
{ name: 'Amount', index: 'Amount', width: 55 },
{ name: 'Store', index: 'Store', width: 50 },
{ name: 'Notes', index: 'Notes', width: 100 }
],
subGrid: true,
subGridModel: [{
name: ['InvNum', 'Name', 'Qauntity'],
width: [55, 200, 80],
params: ['InvNum']
}],
rowNum: 10,
rowList: [10, 20, 50],
pager: '#Div1',
viewrecords: true,
width: 500,
height: 230,
scrollOffset: 0,
loadonce: true,
ignoreCase: true,
gridComplete: function() {
$(".loading").hide();
}
}).jqGrid('navGrid', '#Div1', { del: false, add: false, edit: false }, {}, {}, {}, { multipleSearch: true });
Here the code that I am using in the webservice call to create the JSON data:
IEnumerable orders = getOrders();
IEnumerable items = getItems();
int k = 0;
var jsonData = new
{
totalpages = totalPages, //--- number of pages
page = pageIndex, //--- current page
totalrecords = totalRecords, //--- total items
rows = (
from row in orders
select new
{
id = k++,
cell = new string[] {
row.InvNum.ToString(), row.Amount.ToString(), row.Store, row.Notes
}
}
).ToArray(),
subgrid = (
from row in items
select new
{
cell = new string[] {
row.InvNum.ToString(), row.Name, row.Quantity.ToString()
}
}
).ToArray()
};
result = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);

Resources