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');
}
});