Calling "groupingGroupBy" function cause jqGrid to go into infinite loop. Better suggestion? - jqgrid

When the script used ajax to retrieve saved setting from the database and use it to populate the jqGrid layout setting. That's when it go into infinite loop. Upon some research, it turned out the "groupingGroupBy" function (in jqGrid source code) use "reloadGrid" trigger which doesn't mix well with jqGrid's "beforeRequest" event. I welcome better suggestion. Thanks...
Here's the code...
$('#' + jqgridSpreadsheetId).jqGrid({
url: jqgridWebUrl,
datatype: 'json',
mtype: 'POST',
postData: { WhichJqgridTemplate: jqgridWhichTemplate },
jsonReader: { repeatitems: false },
colNames: ['', 'Id', 'Stock Number', 'VIN', 'Year', 'Make', 'Model', 'Trim', 'Mileage', 'Purchase Price', 'Stock Date', 'Repair Cost', 'Total Cost', 'Days In Inventory', 'Hidden-Inventory-Tracker-Location-Id', 'Inventory Tracker Location', 'Category', 'Links'], //Display Text in Column Header...
colModel: [
//jsonmap --> http://stackoverflow.com/questions/16396229/use-jqgrid-action-formatter...
// --> http://stackoverflow.com/questions/6989608/jqgrid-inline-edit-rows-and-data-not-lining-up...
// --> http://stackoverflow.com/questions/6364473/using-the-jsonmap-property-of-jqgrid-colmodel-with-untyped-json
//action-delete --> http://stackoverflow.com/questions/14732234/how-to-delete-row-in-jqgrid...
//In this case, use "sorttype" property in "colModel" for it to work when "loadonce" is set to true...
//formatter doc --> "http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter&s[]=cell&s[]=formatter"...
//formatter hyperlink --> Stackoverflow posting was said to use formatter's function declaration instead of formatter's "showlink" followed by "formatoptions"...
// --> (Old Link) - http://stackoverflow.com/questions/5010761/linking-from-a-column-value-in-jqgrid-to-a-new-page-using-get...
// --> (New Link) - http://stackoverflow.com/questions/14529358/jqgrid-need-hyperlink-need-to-capture-value-through-jquery/14537512#14537512...
// --> (New Link) - http://www.trirand.com/jqgridwiki/doku.php?id=wiki:custom_formatter...
// --> Reasons are --> 1) far simpiler to use formatter for reading/writing and 2) much quicker and better performance...
{
jsonmap: function (o) { return ''; }, name: 'actDelete', index: 'actDelete', width: 40, align: 'center', sortable: false, hidedlg: true, formatter: 'actions', //"hidedlg" is use to hide the hidden column in "Column Chooser"...
formatoptions: {
keys: false, editbutton: false,
//http://stackoverflow.com/questions/11897649/cant-refresh-jqgrid-with-loadonce-true... (This show us how to reload jqGrid on edit/delete/add, the easy way, when using loadonce:true)...
delOptions: {
url: jqgridWebUrl,
mtype: 'POST',
onclickSubmit: function (objects, rowid) { return { WhichJqgridTemplate: jqgridWhichTemplate, WebpageVehicleVin: $(this).getCell(rowid, jqgridColumnIdVin), WebpageReason: $('textarea[id=#' + jqgridDialogDeleteTextareaId + ']').val() } },
width: 600,
errorTextFormat: function (response) { return "<div style='text-align:center;padding:3px 0px 3px 0px;'>Unable to delete vehicle from Inventory due to an internal error</div>"; },
beforeShowForm: function ($form) {
//http://stackoverflow.com/questions/10035911/jqgrid-inline-delete-selected-row-selrow-is-incorrect... (showed how to use "rowIdOfDeletedRow" in inline-delete dialog)...
//http://stackoverflow.com/questions/6913618/jqgrid-custom-delete-dialog-message... (showed how to customize the inline-delete's message)...
var rowIdOfDeletedRow = $('#DelData>td:nth-child(1)').text();
//Override delete wording message w/ custom message...
$('td.delmsg', $form[0]).html("<div style='padding-top:5px;text-align:center;'>Delete "" + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdYear) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdMake) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdModel) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdTrim) + "" vehicle record?</div>");
//Check to see if textarea exists, if not then create one...
if ($('table.DelTable tr:last td textarea[id=#' + jqgridDialogDeleteTextareaId + ']').length == 0) {
$('table.DelTable tr:last').after('<tr><td style="padding-bottom:10px;vertical-align:top;">Reasons: <textarea id="#' + jqgridDialogDeleteTextareaId + '" rows="2" cols="20" style="width:400px;height:60px;" /></td></tr>'); //display:table-cell;vertical-align:top;...
} else { $('textarea[id=#' + jqgridDialogDeleteTextareaId+']').val(''); }
},
resize: false,
}
},
search: false
}, //"hidedlg" is use to hide the hidden column in "Column Chooser"... //"search" is use to hide the field in search dialog...
{ jsonmap: function (o) { return o.cell[0]; }, name: 'Id', index: 'Id', sortable: false, width: 0, align: 'left', hidden: true, hidedlg: true, search: false }, //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
{ jsonmap: function (o) { return o.cell[1]; }, name: 'StockNumber', index: 'StockNumber', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[2]; }, name: 'Vin', index: 'Vin', sorttype: 'text', width: 190, align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[3]; }, name: 'Year', index: 'Year', sorttype: 'int', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[4]; }, name: 'Make', index: 'Make', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[5]; }, name: 'Model', index: 'Model', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[6]; }, name: 'Trim', index: 'Trim', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[7]; }, name: 'Mileage', index: 'Mileage', sorttype: 'int', align: 'center', formatter: 'number', formatoptions: { decimalSeparator: '', thousandsSeparator: ',', decimalPlaces: 0, defaultValue: '0' } },
{ jsonmap: function (o) { return o.cell[8]; }, name: 'PurchasePrice', index: 'PurchasePrice', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } },
{ jsonmap: function (o) { return o.cell[9]; }, name: 'StockDate', index: 'StockDate', sorttype: 'date', align: 'center', formatter: 'date', formatoptions: { newformat: 'm/d/Y' } }, //"formatter" and "formatoptions" is required for date sorting to works properly...
{ jsonmap: function (o) { return o.cell[10]; }, name: 'RepairCost', index: 'RepairCost', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } },
{ jsonmap: function (o) { return o.cell[11]; }, name: 'TotalCost', index: 'TotalCost', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } }, /*summaryType:'sum' is needed for column grouping to work...*/
{ jsonmap: function (o) { return o.cell[12]; }, name: 'DaysInInventory', index: 'DaysInInventory', sorttype: 'int', align: 'center', formatter: 'number', formatoptions: { decimalSeparator: '', thousandsSeparator: ',', decimalPlaces: 0, defaultValue: '1' } },
{ jsonmap: function (o) { return o.cell[13]; }, name: 'InventoryTrackerLocationId', sortable: false, width: 0, align: 'left', hidden: true, hidedlg: true, search: false }, //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
{ jsonmap: function (o) { return o.cell[14]; }, name: 'InventoryTrackerLocation', index: 'InventoryTrackerLocation', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
{ jsonmap: function (o) { return o.cell[15]; }, name: 'Category', index: 'Category', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
//Links is not present in json data from the website, so we customize it here...
{ jsonmap: function (o) { return ''; }, name: 'Links', index: 'Links', sortable: false, width: 80, align: 'center', hidedlg: true, formatter: function (cellValue, options, rowObject) { return "<span style='text-decoration:underline;cursor:pointer;'>Links</span>" }, search: false } //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
],
pager: '#'+jqgridPagerId,
rowNum: 1000000000, //-1, //10, //06/13/2013 - It is reported that the use of "-1" broke jqGrid when loadonce:true is used. Alternatively, use the max # of rows...
//#rowList: //[5, 10, 20, 50], //Page size dropdown in footer - To show how many rows per page...
rowList: [], //Disable page size dropdown...
pgbuttons: false, //Disable page control like next, back button...
pgtext: null, //Disable pager text line like "Page 0 of 10"...
viewrecords: false, //Disable current view record text like 'View 1-10 of 100'...
caption: 'My Inventory',
width: jqgridLayoutWidth,
shrinkToFit: false, /* This is not reliable */
forceFit: false, /* This is not reliable, plus it it wouldn't work if shrinkToFit is set to false... */
autoWidth: false,
cellLayout: 0, /* This defaulted to 5, so we need to set it to 0 for custom css to works better */
height: 400,
sortable: false, /* Do not allow header-column to shift sideway.. Makes it harder for draggable Group-Header-Column features to work... */ /* Discontinued - This allows both 1) Moving columns sideway to other location fields and 2) for jqGrid Column Chooser Plugin / JQuery Multiselect Plugin to work... */
grouping: true, /* This allows row data to be group into row grouping... */
loadonce: false, /* 06/10/2013 - Set it to false from now on... It is learned that having loadonce:true is not worth the trouble when using search feature, delete feature, etc. so we're better off having client-side do both 1) jqGrid ajaxGridOption and 2) server-side querying to do the heavy work for us... */
//emptyrecords: "No records to display",
ajaxGridOptions: {
beforeSend: function (xhr) { ftnThrobblerAnimationBegin2(); },
complete: function (xhr) { ftnThrobblerAnimationEnd2(); },
error: function (xhr) { alert("An error had occurred, please try again or notify webmaster of this error"); ftnThrobblerAnimationEnd2(); }
},
loadComplete: function () {
JqgridSummarySpreadsheetDisplay();
JqgridGroupedColumnsFormatter();
},
//#loadBeforeSend: function (xhr, settings) { /*Notice: A pre-callback to modify the ajax request object (XMLHttpRequest - xhr) before it is sent. Use this to set custom headers etc. Returning false will cancel the request...*/ },
beforeRequest: function () {
//JqgridColumnChooserSavedBuildsRecordsSetup("INIT", "4444");
$('#' + jqgridSpreadsheetId).jqGrid('groupingGroupBy',
"Make,Model",
{
groupCollapse: true,
groupField: ['name']//,
//08/16/2013 - Appearantly, this "groupText" object is broken and doesn't allow adding "groupText"'s value to recursive grouped column's "groupText" starting with 2nd grouped Columns and after...
// - Use the "jqgridGroupedColumnsFormatter()" function instead under the jqGrid's "loadComplete" attribute...
//groupText: ["<span style='float:left;font-weight:bold;'>{0} - ({1})</span><span style='float:right;font-weight:bold;'> </span>"]
}
);
}
});
Example 1
$('#test').jqGrid({
//.....,
loadComplete: function() {
/* ... */
},
beforeRequest: function() {
/* ... */
},
grouping: true,
groupingView: {
groupField: ["Make","Model"],
groupCollapse: true
}
});
Example 2
$('#test').jqGrid({
//.....,
loadComplete: function() {
/* ... */
},
beforeRequest: function() {
$(this).jqGrid('setGridParam', {
grouping: true,
groupingView: {
groupField: ["Make","Model"],
groupCollapse: true
}
}); //.trigger('reloadGrid');
},
});
Example 3
$('#test').jqGrid({
//.....,
loadComplete: function() {
$(this).jqGrid('setGridParam', {
grouping: true,
groupingView: {
groupField: ["Make","Model"],
groupCollapse: true
}
}); //.trigger('reloadGrid');
},
beforeRequest: function() {
/* ... */
},
});
Example 4
$('#test').jqGrid({
//.....,
loadComplete: function() {
/* ... */
},
beforeRequest: function() {
/* ... */
},
beforeProcessing: function() {
$(this).jqGrid('setGridParam', {
grouping: true,
groupingView: {
groupField: ["Make","Model"],
groupCollapse: true
}
}); //.trigger('reloadGrid');
}
});
Example 5
var blockInfiniteLoopCounter = 0;
$('#test').jqGrid({
//.....,
loadComplete: function() {
/* ... */
},
beforeRequest: function() {
/* ... */
},
beforeProcessing: function() {
if (blockInfiniteLoopCounter == 0) {
blockInfiniteLoopCounter++;
$(this).jqGrid('setGridParam', {
grouping: true,
groupingView: {
groupField: ["Make","Model"],
groupCollapse: true
}
}).trigger('reloadGrid');
}
}
});
Example 6
var $grid = $("#list");
$grid.jqGrid({
datatype: 'json',
url: 'MyInventory-Testcase2.json',
jsonReader: {
repeatitems: false,
id: "Id",
root: function (obj) { return obj; },
page: function () { return 1; },
total: function () { return 1; },
records: function (obj) { return obj.length; }
},
loadonce: true,
colNames: ['Client', 'Date', 'Amount', 'Tax', 'Total', 'Closed', 'Shipped via', 'Notes'],
colModel: [
{name: 'name', width: 65},
{name: 'invdate', width: 80, align: 'center', sorttype: 'date',
formatter: 'date', formatoptions: {newformat: 'd-M-Y'}, datefmt: 'd-M-Y',
searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }},
{name: 'amount', width: 75, },
{name: 'tax', width: 52, },
{name: 'total', width: 65, },
{name: 'closed', width: 80, align: 'center', formatter: 'checkbox',
edittype: 'checkbox', editoptions: {value: 'Yes:No', defaultValue: 'Yes'},
stype: 'select',
searchoptions: {
sopt: ['eq', 'ne'],
value: 'true:Yes;false:No'
}},
{name: 'ship_via', width: 100, align: 'center', formatter: 'select',
edittype: 'select',
editoptions: {
value: 'FE:FedEx;TN:TNT;IN:Intim',
defaultValue: 'Intime'
},
stype: 'select',
searchoptions: {
sopt: ['eq', 'ne'],
value: 'FE:FedEx;TN:TNT;IN:Intim'
}},
{name: 'note', width: 100, sortable: false}
],
cmTemplate: {editable: true},
rowNum: 10,
rowList: [5, 10, 20],
pager: '#pager',
gridview: true,
ignoreCase: true,
rownumbers: false, //true,
sortname: 'invdate',
viewrecords: true,
sortorder: 'desc',
height: '100%',
caption: 'Set grouping dynamically',
beforeProcessing: function() {
//beforeRequest: function() {
//loadComplete: function() {
$(this).jqGrid('setGridParam', {
//grouping: true,
groupingView: { groupCollapse: true, groupField: ["name", "amount"] }
//}); //#.trigger('reloadGrid');
});
}
});
$("#dynamicGrouping").change(function () {
var groupingName = $(this).val();
if (groupingName) {
//$grid.jqGrid('groupingGroupBy', groupingName);
$grid.jqGrid('groupingGroupBy', groupingName, {
// groupField : [groupingName],
groupOrder : ['desc'],
groupColumnShow: [false],
//groupDataSorted : true,
groupCollapse: true
});
} else {
$grid.jqGrid('groupingRemove');
}
});

Example 2 have the following error: you use unneeded {...}. The code beforeRequest: function() {$('#test').jqGrid({'setGridParam', {...}});} should be replace with beforeRequest: function() {$(this).jqGrid('setGridParam', {...});}.
I still see no sense in usage of static groupField values. If you hold the data about groping on the server I would see more sense that the server return information about grouping preferences of the user as the part of server response. In the case you can use beforeProcessing callback to analyse the corresponding part of the server response and to set grouping and groupingView option of jqGrid.
UPDATED: One can fix the example 6 by additional calling of groupingSetup method after setting new groupingView options:
beforeProcessing: function () {
var $this = $(this);
$(this).jqGrid("setGridParam", {
grouping: true,
groupingView: {
groupCollapse: true,
groupField: ["name", "amount"]
}
});
$this.jqGrid("groupingSetup");
}
I prepared the corresponding demo. I use in the demo the JSON data in the following format
{
"groupField": ["name", "amount"],
"rows": [
{ "id": "1", "name": "test", ... },
{ "id": "2", "name": "test2", ... },
...
{ "id": "12", "name": "test12", ... }
]
}
and the following beforeProcessing:
beforeProcessing: function (data) {
var $this = $(this);
$(this).jqGrid("setGridParam", {
grouping: ($.isArray(data.groupField) && data.groupField.length > 0) ?
true :
false,
groupingView: {
groupCollapse: true,
groupField: data.groupField //["name", "amount"]
}
});
$this.jqGrid("groupingSetup");
}
So I get the grouping fields (["name", "amount"]) from the server response.

Related

JqGrid with row specific dropdown?

Here is my current column model:
colModel: [
{ name: 'LastName', index: 'LastName', width: 120, align: 'center' },
{ name: 'FirstName', index: 'FirstName', width: 120, align: 'center' },
{ name: 'MiddleName', index: 'MiddleName', width: 120, align: 'center' },
{ name: 'DOB', index: 'DOB', width: 100, align: 'center' },
{ name: 'id', index: 'id', align: 'center', hidden: true },
{ name: 'checked', index: 'checked', align: 'center', hidden: true },
{ name: 'courtType', index: 'courtType', align: 'center', editable: true, sortable: false, width: 100 },
{ name: 'CaseNumber', index: 'CaseNumber', align: 'center', editable: true, sortable: false, width: 100 },
{ name: 'CourtFileNumber', index: 'CourtFileNumber', align: 'center', editable: true, sortable: false, width: 100 },
{ name: 'WarrantDocket', index: 'WarrantDocket', align: 'center', editable: true, sortable: false, width: 100 },
{ name: 'Sentencing', index: 'Sentencing', align: 'center', editable: true, sortable: false, width: 100 },
{ name: 'notes', index: 'notes', align: 'center', editable: true, sortable: false, width: 400 },
{ name: 'name', index: 'name', width: 200,
sortable: true,
align: 'center',
editable: true,
cellEdit: true,
edittype: 'select',
formatter: 'select',
editoptions: { value: getAllSelectOptions() }
}
],
This gives me a dropdown list from getAllSelectOptions().
function getAllSelectOptions() {
var states = { '1': 'Alabama', '2': 'California', '3': 'Florida',
'4': 'Hawaii', '5': 'London', '6': 'Oxford'
};
return states;
}
Is there a way to get a different list for each row based on its ID and a webmethod call (or some other way)?
var createCourtGridURL = AdminPath + "WebMethods/Kernel/Court.asmx/GetGetdData";
var jqGridDataURL = AdminPath + "WebMethods/Kernel/Court.asmx/GetSelectData";
Edit: Working Code
var myGrid = $('#selectedInmateList'),
decodeErrorMessage = function (jqXHR, textStatus, errorThrown) {
var html, errorInfo, i, errorText = textStatus + '\n' + errorThrown;
if (jqXHR.responseText.charAt(0) === '[') {
try {
errorInfo = $.parseJSON(jqXHR.responseText);
errorText = "";
for (i = 0; i < errorInfo.length; i++) {
if (errorText.length !== 0) {
errorText += "<hr/>";
}
errorText += errorInfo[i].ExceptionType + ": " + errorInfo[i].Message;
}
}
catch (e) { }
} else {
html = /<body.*?>([\s\S]*)<\/body>/i.exec(jqXHR.responseText);
if (html !== null && html.length > 1) {
errorText = html[1];
} else {
errorText = jqXHR.responseText.replace(/\n/, "<br>");
}
}
return errorText;
},
buildSelectFromJson = function (data) {
var html = '<select>', d = data.d, length = d.length, i = 0, item;
for (; i < length; i++) {
item = d[i];
html += '<option value=' + item + '>' + item + '</option>';
}
html += '</select>';
return html;
};
myGrid.jqGrid({
url: createCourtGridURL,
datatype: 'json',
ajaxGridOptions: { contentType: "application/json" },
ajaxSelectOptions: { contentType: "application/json", dataType: 'json'/*, type: "POST"*/ },
serializeGridData: function (postData) {
if (postData.filters === undefined) postData.filters = null;
return JSON.stringify(postData);
},
mtype: 'POST',
colNames: ['Id', 'Last Name', 'First Name', 'Middle Name', 'DOB', 'Checked', 'User'],
colModel: [
{ name: 'id', index: 'id', align: 'center', hidden: true },
{ name: 'LastName', index: 'LastName', width: 120, align: 'center' },
{ name: 'FirstName', index: 'FirstName', width: 120, align: 'center' },
{ name: 'MiddleName', index: 'MiddleName', width: 120, align: 'center' },
{ name: 'DOB', index: 'DOB', width: 100, align: 'center' },
{ name: 'checked', index: 'checked', align: 'center', hidden: true },
{ name: 'User', index: 'User', width: 400, editable: true,
stype: 'select', edittype: 'select',
/*
searchoptions: {
sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'],
dataUrl: jqGridDataURL,
buildSelect: buildSelectFromJson
},
*/
editoptions: {
sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge'],
dataUrl: function () {
var rowID = selectedRowId = myGrid.jqGrid('getGridParam', 'selrow');
return jqGridDataURL + '?id=' + rowID;
},
buildSelect: buildSelectFromJson,
dataEvents: [
{
type: 'change',
fn: function (e) {
//alert('change event')
}
}
]
}
}
],
pager: '#pager',
rowNum: 10,
rowList: [5, 10, 20, 50],
sortname: 'Id',
sortorder: 'desc',
rownumbers: true,
viewrecords: true,
height: '100%',
cellEdit: true,
multiselect: true,
cellsubmit: 'clientArray', //?
pager: '#selectedInmatePager',
gridview: true,
jsonReader: {
root: "d.rows",
page: "d.page",
total: "d.total",
records: "d.records",
cell: ""
},
caption: 'Selected Court Inmates',
loadError: function (jqXHR, textStatus, errorThrown) {
// remove error div if exist
$('#' + this.id + '_err').remove();
// insert div with the error description before the grid
myGrid.closest('div.ui-jqgrid').before(
'<div id="' + this.id + '_err" style="max-width:' + this.style.width +
';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left"/></div>');
},
loadComplete: function () {
// remove error div if exist
$('#' + this.id + '_err').remove();
}
});
myGrid.jqGrid('navGrid', '#selectedInmatePager', { add: false, edit: true, del: false },
{}, {}, {}, { multipleSearch: true, overlay: false, width: 480 });
You use dataUrl already. jqGrid supports dataUrl starting with 4.5.3. So you can define dataUrl as callback which get tree parameters rowid, value, columnName. So you can return from the dataUrl the URL which contains rowid as parameter. In the case the call to the dataUrl will be different for different rows any you can implement your requirements.

Unable to get property 'stype' of undefined or null reference

I using jqgrid filtertoolbar. I'm having some 4 select filter in that. When i tried to select one of the values in any select box i'm getting the following error.
Unable to get property 'stype' of undefined or null reference
Is there any general error or missing value that i have done anywhere in my code.
//Code:
Sample of colModel:
colModel:
jQuery.ajax({
url: 'ManageCandidateDetails.aspx/GetAllCandidateDetails',
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
// debugger;
genericResult = $.parseJSON(data.d);
// debugger;
jQuery("#CandidateDetailsGrid").jqGrid({
data: genericResult.candidateDetails,
datatype: "local",
// colNames: ['CandidateId', 'Email', 'Name'],
//colModel: [{ name: 'CandidateId', index: 'CandidateId', width: 75}, { name: 'Email', index: 'Email', width: 75 }, { name: 'Name', index: 'Name', width: 100}],
colNames: ['CandidateId', 'Name', 'Email', 'DOB', 'Gender', 'Qualification', 'Department', 'OtherQual', 'OtherDept', 'Exp(Years)', 'Exp(Months)', 'Mobile', 'Country', 'State', 'City', 'ZipCode', 'FilePath', 'Sel.Status', 'CreatedDate', 'ModifiedDate', 'ModifiedBy', 'Status', 'LastLoginTime'],
colModel: [{ name: 'CandidateId', index: 'CandidateId', width: 75, editable: true },
{ name: 'Name', index: 'Name', width: 100, editable: true },
{ name: 'Email', index: 'Email', width: 75, editable: true },
{ name: 'DOB', index: 'DOB', width: 50, editable: true, searchoptions: { dataInit: newDatePick }, editoptions: { dataInit: newDatePick} },
{ name: 'Gender', index: 'Gender', width: 50, editable: true },
{ name: 'Qualification', index: 'Qualification', width: 75, editable: true, stype: 'select', editoptions: { value: ":All;" + genericResult.qualification} },
{ name: 'Department', index: 'Department', width: 75, editable: true, stype: 'select', editoptions: { value: ":All;" + genericResult.department} },
{ name: 'OtherQual', index: 'OtherQual', width: 75, editable: true },
{ name: 'OtherDept', index: 'OtherDept', width: 75, editable: true },
{ name: 'ExperienceYears', index: 'ExperienceYears', width: 75, editable: true },
{ name: 'ExperienceMonths', index: 'ExperienceMonths', width: 75, editable: true },
{ name: 'Mobile', index: 'Mobile', width: 100, editable: true },
{ name: 'Country', index: 'Country', width: 100, editable: true, stype: 'select', formatter: 'select', edittype: 'select',
searchoptions: {
value: allCountries, stype: 'select'
},
editoptions: {
value: allCountries,
dataInit: removeTheOptionAll,
dataEvents: [
{ type: "change", fn: function (e) { changeStateSelect($(e.target).val(), e.target); } }
]
}
},
{ name: 'state', index: 'state', width: 100, formatter: "select", stype: "select",
editable: true, edittype: "select",
editoptions: { value: allStates, dataInit: removeTheOptionAll },
searchoptions: { value: allStates }
},
{ name: 'City', index: 'City', width: 50, editable: true },
{ name: 'ZipCode', index: 'ZipCode', width: 50, editable: true },
{ name: 'FilePath', formatter: function () { return "<img src='../Images/error.png' alt='my image' />"; }, unformat: imageUnFormat, index: 'FilePath', width: 50 },
{ name: 'SelectedStatus', index: 'SelectedStatus', width: 75, edittype: 'checkbox', formatter: 'checkbox', editable: true, editoptions: { value: "1:Yes;0:No" }, stype: 'select', searchoptions: { sopt: ['eq'], value: "All:All;1:Yes;0:No"} },
{ name: 'CreatedDate', index: 'CreatedDate', width: 75, formatoptions: { srcformat: "ISO8601Long", newformat: "d/m/Y h:i A" },
searchoptions: { dataInit: datePick }, editoptions: { dataInit: datePick }
},
{ name: 'ModifiedDate', index: 'ModifiedDate', width: 75, formatoptions: { srcformat: "ISO8601Long", newformat: "d/m/Y h:i A" },
searchoptions: { dataInit: datePick }, editoptions: { dataInit: datePick }
},
{ name: 'Modifiedby', index: 'ModifiedBy', width: 75 },
{ name: 'Status', index: 'Status', width: 50, edittype: 'checkbox', editable: true, stype: 'select', searchoptions: { value: "All:All;1:Yes;2:No"} },
{ name: 'LastLoginTime', index: 'LastLoginTime', width: 75, formatoptions: { srcformat: "ISO8601Long", newformat: "d/m/Y h:i A" },
searchoptions: { dataInit: datePick, attr: { title: 'Select Date'} }, editoptions: { dataInit: datePick }
}],
rowNum: 10,
mtype: 'GET',
loadonce: true,
rowList: [10, 20, 30],
pager: '#CandidateDetailsGridPager',
sortname: 'CandidateId',
viewrecords: true,
caption: "Candidate Details",
ignoreCase: true,
gridview: true,
rownumbers: true
});
jQuery("#CandidateDetailsGrid").jqGrid('filterToolbar', { stringResult: true, searchOnEnter: false, defaultSearch: "cn" });
$('#CandidateDetailsGrid').jqGrid('navGrid', '#CandidateDetailsGridPager',
{
edit: true,
add: true,
del: true,
search: true,
searchtext: "Search",
addtext: "Add",
edittext: "Edit",
deltext: "Delete"
},
{ // edit option
beforeShowForm: function (form) {
}
},
{ // add option
addcaption: 'Add Candidate Detail',
beforeShowForm: function (form) {
//debugger;
$("#myFormError").remove();
$('#tr_LastLoginTime', form).hide();
$('#tr_CandidateId', form).hide();
$('#tr_Modifiedby', form).hide();
$('#tr_ModifiedDate', form).hide();
$('#tr_CreatedDate', form).hide();
},
onclickSubmit: function (response, postData) {
debugger;
$("#FormError").text("");
$("<tr id='myFormError'><td colspan='2'><div style='background-color:green;color:white; font-weight:bold; width:100%;padding-left:5px;'>Success</div></td></tr>").insertAfter("#FormError");
}
}
);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
}
});
//Unformat the image during the edit.
function imageUnFormat(cellvalue, options, cell) {
return cellvalue
}

how to set the jqgrid column width, and re-sizable, in a scrollable jqgrid?

i am using jqgrid and facing a problem with column width
here is my js code
jQuery(document).ready(function () {
var grid = jQuery("#grid");
grid.jqGrid({
url: '/Admin/GetUserForJQGrid',
datatype: 'json',
mtype: 'Post',
cellsubmit: 'remote',
cellurl: '/Admin/GridSave',
//formatCell: emptyText,
colNames: ['Id', 'Privileges', 'First Name', 'Last Name', 'User Name', 'Password', 'Password Expiry', 'Type', 'Last Modified', 'Last Modified By', 'Created By', ''],
colModel: [
{ name: 'Id', index: 'Id', key: true, hidden: true, editrules: { edithidden: true } },
{ name: 'Privileges', index: 'Privileges', width: "350", resizable: false, editable: false, align: 'center', formatter: formatLink, classes: 'not-editable-cell' },
{ name: 'FirstName', index: 'FirstName', width:350, align: "left", sorttype: 'text', resizable: true, editable: true, editrules: { required: true } },
{ name: 'LastName', index: 'LastName',width:350, align: "left", sorttype: 'text', resizable: true, editable: true, editrules: { required: true } },
{ name: 'UserName', index: 'UserName', width:300,align: "left", sorttype: 'text', resizable: true, editable: true, editrules: { required: true } },
{ name: 'Password', index: 'Password',width:400, align: "left", sorttype: 'text', resizable: true, editable: false, editrules: { required: true }, classes: 'not-editable-cell' },
{
name: 'Password_Expiry',width:250, index: 'Password_Expiry', align: "left", resizable: true, editable: true, editoptions: {
size: 20, dataInit: function (el) {
jQuery(el).datepicker({
dateFormat: 'yy-mm-dd', onSelect: function (dateText, inst) {
jQuery('input.hasDatepicker').removeClass("hasDatepicker")
return true;
}
});
}
}
},
{
name: 'Type', width: "250", index: 'Type', sorttype: 'text', align: "left", resizable: true, editable: true, editrules: { required: true }, edittype: 'select', editoptions: {
value: {
'Normal': 'Normal',
'Sales': 'Sales',
'Admin': 'Admin',
'SuperAdmin': 'SuperAdmin'
},
dataEvents: [
{
type: 'change',
fn: function (e) {
var row = jQuery(e.target).closest('tr.jqgrow');
var rowId = row.attr('id');
jQuery("#grid").saveRow(rowId, false, 'clientArray');
}
}
]
}
},
{ name: 'Modified',width:250, index: 'Modified', sorttype: 'date', align: "left", resizable: true, editable: false, classes: 'not-editable-cell' },
{ name: 'ModifiedBy', width:250, index: 'ModifiedBy', sorttype: 'text', align: "left", resizable: true, editable: false, classes: 'not-editable-cell' },
{ name: 'CreatedBy', width:250,index: 'CreatedBy', sorttype: 'text', align: "left", resizable: true, editable: false, classes: 'not-editable-cell' },
{ name: 'Delete',width:50, index: 'Delete', width: 25, resizable: false, align: 'center', classes: 'not-editable-cell' }
],
rowNum: 10,
rowList: [10, 20, 50, 100],
sortable: true,
delete: true,
pager: '#pager',
height: '100%',
width: "650",
afterSubmitCell: function (serverStatus, rowid, cellname, value, iRow, iCol) {
var response = serverStatus.responseText;
var rst = 'false';
debugger;
if (response == rst) {
debugger;
setTimeout(function () {
$("#info_dialog").css({
left: "644px", // new left position of ERROR dialog
top: "380px" // new top position of ERROR dialog
});
}, 50);
return [false, "User Name Already Exist"];
}
else {
return [true, ""];
}
},
//rowNum: 10,
//rowList: [10, 20, 50, 100],
sortable: true,
loadonce: false,
ignoreCase: true,
caption: 'Administration',
search: false,
del: true,
cellEdit: true,
hidegrid: false,
pgbuttons : false,
pginput : false,
//viewrecords: true,
gridComplete: function () {
var ids = grid.jqGrid('getDataIDs');
for (var i = 0; i < ids.length; i++) {
var isDeleted = grid.jqGrid('getCell', ids[i], 'Delete');
if (isDeleted != 'true') {
grid.jqGrid('setCell', ids[i], 'Delete', '<img src="/Images/delete.png" alt="Delete Row" />');
}
else {
grid.jqGrid('setCell', ids[i], 'Delete', ' ');
}
}
}
}
);
grid.jqGrid('navGrid', '#pager',
{ resize: false, add: false, search: false, del: false, refresh: false, edit: false, alerttext: 'Please select one user' }
).jqGrid('navButtonAdd', '#pager',
{ title: "Add New users", buttonicon: "ui-icon ui-icon-plus", onClickButton: showNewUsersModal, position: "First", caption: "" });
});
i need a scrollable grid , when use come to this page i have to show the first 7 columns only just seven in full page. i have 11 columns in my grid rest of the columns can be seen by using scroll, but first 7 should be shown when grid loads. and every column should be re-sizable. can any body help me, i will 100% mark your suggestion if it works for me ...thank you ;) . if something is not explained i am here to explain please help me
and can i save the width of column permanently when user re-size the column, so when next time grid get loads the column should have the same width which is set by the user by re-sizing.. is it possible ?
I am not sure what you want,but you can auto adjust the width with JqGrid autowidth and shrinkToFit options.
Please refer this Post jqGrid and the autowidth option. How does it work?
this will do the trick.

jqgrid validation when editing a record

I have now a problem with validation of a record that is being edited.
The edit form (and the add form) has a field called "email". That field should be unique in database, so I use ajax to validate it, by mean of this function:
function check_email(value, colname) {
$.ajax({
url: '#Url.Action("CheckEmail")',
data: { email: value },
type: 'POST',
async: false,
datatype: 'text',
success: function (data) {
if (!data) result = [true, ""];
else result = [false, colname + ": ya existe en el sistema"];
}
})
return result;
}
This works, but the problem is when I am editing the record. Of course e-mail exists in this case, so it is not allowing me to save the record.
The algorithm might be: it should validate only if id is > 0 and the entered e-mail is different from the existing value. In other words, validation must occur if the user is changing e-mail.
I spent a lot of time trying to figure out how to know if the editform is for adding or for editing, and even more, I was trying to find the value of the primary key of the record being edited, without any success.
Any help will be appreciated,
EDIT:
This is the code of the grid:
$("#personal").jqGrid({
url: "#Url.Action("List")",
datatype: "json",
mtype: "GET",
colNames: ["Departamento",
"Nombres",
"Apellido Paterno",
"Apellido Materno",
"RUT",
"Contraseña",
"Fecha Nacimiento",
"Fotografía",
"Estado Civil",
"Género",
"Dirección",
"Cargo",
"E-mail",
"Fecha Ingreso",
"Creación",
"Modificación"],
colModel: [
{ name: "dep_id", index: "dep_nombre", editable: true, edittype: "select", formatter: 'select', editoptions: { width: 100, value: "#ViewData["Departamentos"]" }, width: 250, editrules: { required: true }, formoptions: { elmsuffix: '<span class="required">*</span>' }, stype: 'select', searchoptions: { sopt: ['eq'], value: "#ViewData["Departamentos"]" } },
{ name: "per_nombres", index: "per_nombres", editable: true, width: 250, editoptions: { maxlength: 80, size: 32 }, editrules: { required: true }, formoptions: { elmsuffix: '<span class="required">*</span>' } },
{ name: "per_apellido_paterno", index: "per_apellido_paterno", editable: true, width: 250, editoptions: { maxlength: 80, size: 32 }, editrules: { required: true }, formoptions: { elmsuffix: '<span class="required">*</span>' } },
{ name: "per_apellido_materno", index: "per_apellido_materno", editable: true, width: 250, editoptions: { maxlength: 80, size: 32 } },
{ name: "per_dni", index: "per_dni", editable: true, width: 100, editoptions: { maxlength: 20, size: 17, dataInit: function (el) { $.mask.definitions['~'] = '[0-9kK]'; $(el).mask("?99.999.999-~"); } }, editrules: { required: true, custom: true, custom_func: is_rut }, formoptions: { elmsuffix: '<span class="required">*</span>' }, searchoptions: { dataInit: function (el) { $.mask.definitions['~'] = '[0-9kK]'; $(el).mask("?99.999.999-~"); } } },
{ name: "per_contrasena", editable: true, edittype: "password", hidden: true, width: 100, editoptions: { maxlength: 50, size: 17 }, editrules: { required: false, edithidden: true } },
{ name: "per_fecha_nacimiento", index: "per_fecha_nacimiento", editable: true, width: 100, editrules: { date: true, required: false }, formatter: 'date', formatoptions: { srcformat: 'SortableDateTime', newformat: 'd-m-Y' }, editoptions: { size: 17, dataInit: function (el) { $(el).datepicker({ dateFormat: 'dd-mm-yy' }); $(el).mask("?99-99-9999"); } }, searchoptions: { dataInit: function (el) { $(el).datepicker({ dateFormat: 'dd-mm-yy' }); $(el).mask("?99-99-9999"); } } },
{ name: "per_fotografia", index: "per_fotografia", editable: true, width: 250, edittype: "file", editoptions: { maxlength: 255, size: 32 } },
{ name: "per_estado_civil", index: "per_estado_civil", editable: true, edittype: "select", editoptions: { value: ":;S:Soltero;C:Casado;V:Viudo;D:Divorciado" }, width: 100, stype: 'select', searchoptions: { sopt: ['eq'], value: ":;S:Soltero;C:Casado;V:Viudo;D:Divorciado" } },
{ name: "per_sexo", index: "per_sexo", editable: true, edittype: "select", editoptions: { value: ":;M:Masculino;F:Femenino" }, width: 100, stype: 'select', searchoptions: { sopt: ['eq'], value: ":;M:Masculino;F:Femenino" } },
{ name: "per_direccion", index: "per_direccion", editable: true, width: 250, editoptions: { maxlength: 512, size: 32 } },
{ name: "per_cargo", index: "per_cargo", editable: true, width: 100, editoptions: { maxlength: 50, size: 32 } },
{ name: "per_email", index: "per_email", editable: true, width: 100, editoptions: { maxlength: 80, size: 32 }, editrules: { email: true, required: false, custom: true, custom_func: check_email } },
{ name: "per_fecha_ingreso", index: "per_fecha_ingreso", editable: true, width: 100, editrules: { date: true, required: false }, formatter: 'date', formatoptions: { srcformat: 'SortableDateTime', newformat: 'd-m-Y' }, editoptions: { size: 17, dataInit: function (el) { $(el).datepicker({ dateFormat: 'dd-mm-yy' }); $(el).mask("?99-99-9999"); } }, searchoptions: { dataInit: function (el) { $(el).datepicker({ dateFormat: 'dd-mm-yy' }); $(el).mask("?99-99-9999"); } } },
{ name: "per_creado_el", index: "per_creado_el", editable:false, search:false, width: 100, align: "center", formatter: "date" },
{ name: "per_modificado_el", index: "per_modificado_el", editable:false, search:false, width: 100, align: "center", formatter: "date" },
],
jsonReader: {
repeatitems: false,
id: "per_id"
},
pager: "#pager",
rowNum: 10,
rowList: [10, 20, 30],
sortname: "per_apellido_paterno",
sortorder: "asc",
viewrecords: true,
gridview: true,
autoencode: true,
multiselect: true,
shrinkToFit: false,
caption: "Funcionarios",
editurl: "#Url.Action("AjaxEdit")",
height: '100%',
width: 935,
rownumbers: true,
rownumWidth: 40
});
$("#personal").jqGrid('hideCol', ["per_fotografia", "per_direccion"]);
$("#personal").jqGrid('navGrid', '#pager', { edit: true, add: true, del: true, search: false }, { width: 500 }, { width: 500 }, {}, { multipleSearch: false, multipleGroup: false });
$("#personal").jqGrid('filterToolbar', { searchOperators: false });
$.jgrid.edit.addCaption = "Agregar Funcionario";
$.jgrid.edit.editCaption = "Modificar Funcionario";
$.jgrid.edit.saveData = "¡El funcionario fue modificado! ¿Almacena los cambios?";
$.jgrid.formatter.date.newformat = 'd-m-Y H:i';
Thanks
Jaime
I think you should send the record ID for verification.
function check_email(value, colname) {
var rowid = jQuery('#personal').jqGrid('getGridParam', 'selrow');
$.ajax({
url: '#Url.Action("CheckEmail")',
data: { email: value, rowid: rowid },
type: 'POST',
async: false,
datatype: 'text',
success: function (data) {
if (!data) result = [true, ""];
else result = [false, colname + ": ya existe en el sistema"];
}
})
return result;
}
and so the server has any record can be checked with the ID does not match with the rowid.

problem loading data in details jqGrid from master grid?

When I am making a call first time it shows data in my details grid from master grid but when selecting other row its not populating the new data in the details grid..
jQuery("#list10").jqGrid({
sortable: true,
url: '/cpsb/unprocessedOrders.do?method=getInitialUnprocessedList',
datatype: 'json',
colNames: ['Order', 'Load', 'Gate Time', 'Stop', 'Customer', 'Status'],
colModel: [
{ name: 'orderNumber', index: 'orderNumber', width: 120, align: "center",
sorttype: "int", key: true },
{ name: 'loadNumber', index: 'loadNumber', width: 100, align: "center",
sorttype: "int" },
{ name: 'latestTime', index: 'latestTime', width: 160, align: "center",
align: "center" },
{ name: 'stopSeq', index: 'stopSeq', width: 80, align: "center",
sorttype: "int" },
{ name: 'customerNumber', index: 'customerNumber', width: 60,
align: "center", sorttype: "int" },
{ name: 'orderStatus', index: 'orderStatus', width: 120, align: "center" }
],
rowNum: 10,
rowList: [10, 20, 30],
jsonReader: { repeatitems: false,
root: function (obj) {
return obj;
},
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.length; }
},
pager: '#pager10',
sortname: 'Gate Time',
sortorder: "desc",
gridview: true,
loadonce: true,
viewrecords: true,
multiselect: true,
multikey: 'ctrlKey',
caption: "Order Header",
onSelectRow: function (ids) {
if (ids == null) {
ids = 0;
if (jQuery("#list10_d").jqGrid('getGridParam', 'records') > 0) {
jQuery("#list10_d").jqGrid('setGridParam', { url:
"/cpsb/unprocessedOrders.do?method=getUnprocessedOrderDetails&orderNum=" + ids });
jQuery("#list10_d").jqGrid('setCaption',
"Order Header: " + ids).trigger('reloadGrid');
}
}
else {
jQuery("#list10_d").jqGrid('setGridParam', { url:
"/cpsb/unprocessedOrders.do?method=getUnprocessedOrderDetails&orderNum=" + ids });
jQuery("#list10_d").jqGrid('setCaption',
"Order Details: " + ids).trigger('reloadGrid');
}
},
height: '100%'
});
jQuery("#list10").jqGrid('navGrid','#pager10',
{view:true,add:false,edit:false,del:false,searchtext:"Filter"},
{},{},{},{multipleSearch:true});
$("#list10").jqGrid('hideCol', 'cb');
2nd grid for order details
jQuery("#list10").jqGrid('reloadGrid');
jQuery("#list10_d").jqGrid({
height: 100,
url: "/cpsb/unprocessedOrders.do?method=getUnprocessedOrderDetails&orderNum=",
datatype: "json",
colNames: ['Order', 'SKU', 'UPC', 'Item Description', 'Quantity Ordered',
'Teach in Hold?'],
colModel: [
{ name: 'orderNumber', index: 'orderNumber', width: 55 },
{ name: 'sku', index: 'sku', width: 55 },
{ name: 'upc', index: 'upc', width: 40, align: "right" },
{ name: 'itemDescription', index: 'itemDescription', width: 150,
align: "right" },
{ name: 'quantityOrdered', index: 'quantityOrdered', width: 150,
align: "right", sortable: false, search: false },
{ name: 'teachInId', index: 'teachInId', width: 150,
align: "right", editable: true, edittype: "checkbox",
formatter: 'checkbox', editoptions: { value: "true:false"} }],
rowNum: 5,
rowList: [5, 10, 20],
jsonReader: { repeatitems: false,
root: function (obj) {
return obj;
},
page: function (obj) { return 1; },
total: function (obj) { return 1; },
records: function (obj) { return obj.length; }
},
pager: '#pager10_d',
sortname: 'SKU',
loadonce: true,
viewrecords: true,
sortorder: "asc",
multiselect: true,
multikey: 'ctrlKey',
caption: "Order Detail",
height: '100%'
}).navGrid('#pager10_d', { view: true, add: false, edit: false, del: false },
{}, {}, {}, { multipleSearch: true });
$("#list10_d").jqGrid('hideCol', 'cb');
jQuery("#ms1").click(function () {
var s;
s = jQuery("#list10_d").jqGrid('getGridParam', 'selarrrow');
alert(s);
});
Edit: I am able view different records once I refresh the page...But after one selection other selection don't work
edit2: after debugging i saw that I am appending the orderNum parameter correctly but this is not making any call to the action class....any idea? thanks!
It seems to me that the answer on your main problem you find here: JqGrid Reload not working.
Because you use loadonce:true in both grids, the datatype in every grid will be changed from "json" to "local" after the first load. It seems to me that you should just remove loadonce:true for the second (detailed) grid. If you do want use loadonce:true for example for local sorting or local paging, then you should reset datatype to "json" in the same call jQuery("#list10_d").jqGrid('setGridParam',{url:"...", datatype: "json"}); .

Resources