I have been upgrading my projects to jQuery 1.12.0 and the latest version of free jqGrid. I am now seeing an field undefined error here in jquery.jqGrid.src.js
:
this.execute = function() {
var match = _query, results = [];
if (match === null) {
return self;
}
$.each(_data, function() {
if (eval(match)) { results.push(this); }
});
_data = results;
return self;
};
The match string looks like:
(String(ErrorCells).toUpperCase() !== String("0").toUpperCase())
I'm filtering out rows with errors (ErrorCells
is used as a bit field), but it looks like an explicit this.ErrorCells
is necessary. I can't wrap my head around what exactly changed and if there is a resolution without modifying the jqGrid source.
**** UPDATE ****
Below you can see that in the $.each
handler, ErrorCells
is undefined, but this.ErrorCells
is.
This is the code extending the postdata
with the filtering criteria:
$.extend(postdata, { // - set filter condition
filters: '',
searchField: 'ErrorCells',
searchOper: 'ne',
searchString: '0'
});
$grid.jqGrid('setGridParam', { search: true, postData: postdata });
$grid.trigger('reloadGrid', [{ page: 1}]);
and this is the grid configuration:
$grid.jqGrid({
url: "Loader.svc/GetData", // - web invoke post
editurl: "clientArray", // - normally the endpoint to post edits, in this case we just edit local data
postData: { "uniqueFolder": uniqueFolder, "xlsName": xlsName, "solIds": GetSolIdString(), "subcompany": _selectedConfiguration.MYSUBCOMPANY, "requireSolId": _selectedConfiguration.MYISBRANCHIDREQ },
datatype: "json",
loadonce: true, // - load data once on server side, then switch to local data handling
mtype: "POST",
ajaxGridOptions: { contentType: "application/json", cache: false },
serializeGridData: function(postData) {
return JSON.stringify(postData);
},
jsonReader: {
id: "Id",
root: function(obj) { return obj.rows; },
page: function(obj) { return obj.page; },
total: function(obj) { return obj.total; },
records: function(obj) { return obj.records; }
},
headertitles: true,
search: true,
rowNum: 15, // - rows per page
rowList: [5, 10, 15, 20], // - options for rows per page
pager: "#pager", // - element anchor for navigation panel
gridview: true, // - row at once binding (faster performance)
autoencode: true, // - encode html data
ignoreCase: true, // - searches are case-insensitive
//sortname: "IDNumber", // - sort column for initial load
viewrecords: true, // - displays the beginning and ending record number in the grid, out of the total number of records in the query
sortorder: "asc",
caption: "Card Personalization",
height: "100%",
shrinkToFit: false, // - defines how the width of the columns of the grid should be re-calculated, taking into consideration the width of the grid
autowidth: true,
multiselect: false,
loadui: "disable",
colNames: ["IDType", "IDNumber", "LastName", "FirstName", "MiddleInitial", "EmbossLine1", "EmbossLine2", "Address1", "Address2", "Address3", "City", "Country", "State",
"PostalCode", "DateOfBirth", "EmailAddress", "HomePhone", "OfficePhone", "MobilePhone", "PhotoReference", "SalaryID", "SolID", "IDImage", "ErrorCells", "ErrorDescriptions", "IDThumb"],
colModel: [
{ name: "IDType", width: 80, align: "left", editable: true, sortable: true, sorttype: "integer",
stype: "select",
edittype: "select",
formatter: "select",
formoptions: { elmprefix: "<font color='red'>*</font>" },
searchoptions: { sopt: ["eq"], value: GetIdTypes(true) },
editrules: { required: true, integer: true, minValue: 1, maxValue: 50 },
editoptions: { value: GetIdTypes(false), dataInit: function(elem) { $(elem).width(150); } },
searchOptions: { defaultValue: 4 },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(0, rawObject); }
},
{ name: "IDNumber", width: 80, align: "left", editable: true, sortable: true,
editrules: { required: true, custom: true, custom_func: validateIDNumber },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(1, rawObject); }
},
{ name: "LastName", width: 100, align: "left", editable: true, sortable: true,
editrules: { required: true, custom: true, custom_func: validateName },
editoptions: { maxlength: 200 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(2, rawObject); }
},
{ name: "FirstName", width: 100, align: "left", editable: true, sortable: true,
editrules: { required: true, custom: true, custom_func: validateName },
editoptions: { maxlength: 200 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(3, rawObject); }
},
{ name: "MiddleInitial", width: 70, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validateName },
editoptions: { maxlength: 40 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(4, rawObject); }
},
{ name: "EmbossLine1", width: 100, align: "left", editable: true, sortable: true, search: false,
editrules: { required: $('#cbFirstLineEmbossing').prop('checked'), custom: true, custom_func: validateEmbossline },
editoptions: { maxlength: 19, dataInit: function(el) { $(el).css('text-transform', 'uppercase'); } },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(5, rawObject); }
},
{ name: "EmbossLine2", width: 100, align: "left", editable: true, sortable: true, search: false,
editrules: { required: $('#cbSecondLineEmbossing').prop('checked'), custom: true, custom_func: validateEmbossline },
editoptions: { maxlength: 19, dataInit: function(el) { $(el).css('text-transform', 'uppercase'); } },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(6, rawObject); }
},
{ name: "Address1", width: 200, align: "left", editable: true, sortable: true, search: false,
editrules: { required: true, custom: true, custom_func: validateAddress },
editoptions: { maxlength: 50 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(7, rawObject); }
},
{ name: "Address2", width: 200, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validateAddress },
editoptions: { maxlength: 50 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(8, rawObject); }
},
{ name: "Address3", width: 200, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validateAddress },
editoptions: { maxlength: 50 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(9, rawObject); }
},
{ name: "City", width: 100, align: "left", editable: true, sortable: true,
editrules: { required: true, custom: true, custom_func: validateCity },
editoptions: { maxlength: 50 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(10, rawObject); }
},
{ name: "Country", width: 50, align: "left", editable: true, edittype: "select", stype: "select", sortable: true,
editrules: { required: true, custom: true, custom_func: validateCountry },
formoptions: { elmprefix: "<font color='red'>*</font>" },
searchoptions: {
value: GetCountries(true),
dataInit: function(elem) {
var v = $(elem).val();
if (v !== '')
setStateValues(v, true);
},
dataEvents: [
{ type: "change", fn: function(e) { changeStateSelect($(e.target).val(), e.target); } },
{ type: "keyup", fn: function(e) { $(e.target).trigger('change'); } }
]
},
editoptions: {
maxlength: 2,
value: GetCountries(false),
dataInit: function(elem) { // - populate the state dropdown based on selected country
var v = $(elem).val();
if (v !== '')
setStateValues(v, false);
setTimeout(function() {
var $element = $(elem),
required = $element.val() === 'US';
$grid.jqGrid('setColProp', 'PostalCode', { editrules: { required: required} });
$('#PostalCode').siblings('.mystar').html(required ? '*' : ' ');
$element.width(150);
}, 100);
},
dataEvents: [
{ type: "change", fn: function(e) {
changeStateSelect($(e.target).val(), e.target);
var required = $(e.target).val() === 'US';
$grid.jqGrid('setColProp', 'PostalCode', { editrules: { required: required} });
$('#PostalCode').siblings('.mystar').html(required ? '*' : ' ');
}
},
{ type: "keyup", fn: function(e) { $(e.target).trigger('change'); } }
]
},
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(11, rawObject); }
},
{ name: "State", width: 50, align: "left", editable: true, edittype: "select", stype: "select", sortable: true,
editrules: { required: true, custom: true, custom_func: validateState },
formoptions: { elmprefix: "<font color='red'>*</font>" },
editoptions: {
value: {},
maxlength: 4,
dataInit: function(elem) { $(elem).width(150); }
},
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(12, rawObject); }
},
{ name: "PostalCode", width: 70, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validatePostal },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: "<span class='mystar' style='color:red'> </span>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(13, rawObject); }
},
{ name: "DateOfBirth", width: 80, align: "left", editable: true, sortable: true, sorttype: "date", search: false,
editrules: { required: true, date: true, custom: true, custom_func: validateDate },
formoptions: { elmprefix: "<font color='red'>*</font>", elmsuffix: " format: mm/dd/yyyy" },
editoptions: {
size: 10,
maxlength: 10,
dataInit: function(element) {
$(element).datepicker({
dateFormat: "mm/dd/yy", changeMonth: true, changeYear: true, yearRange: "-100y:c+nn", maxDate: "-1d"
}).mask('99/99/9999');
}
},
datefmt: 'mm/dd/yyyy',
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(14, rawObject); }
},
{ name: "EmailAddress", width: 150, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validateEmail },
editoptions: { maxlength: 100 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(15, rawObject); }
},
{ name: "HomePhone", width: 100, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validatePhone },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(16, rawObject); }
},
{ name: "OfficePhone", width: 100, align: "left", editable: true, sortable: true, search: false,
editrules: { required: false, custom: true, custom_func: validatePhone },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(17, rawObject); }
},
{ name: "MobilePhone", width: 100, align: "left", editable: true, sortable: true,
editrules: { required: true, custom: true, custom_func: validatePhone },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(18, rawObject); }
},
{ name: "PhotoReference", width: 100, align: "left", editable: true, sortable: true, search: false,
editrules: { required: true },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(19, rawObject); }
},
{ name: "SalaryID", width: 100, align: "left", editable: true, sortable: true, search: true,
editrules: { required: false, custom: true, custom_func: validateSalaryIdLocal },
editoptions: { maxlength: 30 },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(20, rawObject); }
},
{ name: "SolID", width: 50, align: "left", editable: true, sortable: true, edittype: "select", stype: "select",
editrules: { required: true /*, custom: true, custom_func: validateSolId*/ },
editoptions: { value: GetSolIds(_selectedConfiguration, false), maxlength: 4 },
searchoptions: { sopt: ["eq"], value: GetSolIds(_selectedConfiguration, true) },
formoptions: { elmprefix: "<font color='red'>*</font>" },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(21, rawObject); }
},
{ name: "IDImage", width: 100, align: "left", editable: true, sortable: true, search: true,
editrules: { required: false, custom: true, custom_func: _validateIDImagePath },
editoptions: { maxlength: 150, readonly: true },
formoptions: { elmprefix: " " },
cellattr: function(rowId, tv, rawObject, cm, rdata) { return SetCellError(22, rawObject); }
},
{ name: "ErrorCells", hidden: true, editoptions: { defaultValue: '0'} },
{ name: "ErrorDescriptions", hidden: true },
{ name: "IDThumb", width: 50, fixed: true,
formatter: function(cellvalue, options, rowObject) {
return '<a id="imgSource_' + options.rowId + '" href="" data-lightbox="image_' + options.rowId + '" data-title=""><img id="imgThumb_' + options.rowId + '" src="" width="30" height="30"></a>';
}
}],
ondblClickRow: function(rowid, ri, ci) { // - double click event handler
var p = $grid[0].p;
if (p.selrow !== rowid) // prevent the row from be unselected on double-click
$grid.jqGrid('setSelection', rowid);
$grid.jqGrid('editGridRow', rowid, editSettings); // - form edit
},
onSelectRow: function(id) { // - select row event handler
if (id && id !== lastSel) {
$grid.jqGrid('restoreRow', lastSel);
lastSel = id;
}
},
beforeRequest: function() { // - on initial load, display empty grid for editing
if (_initialLoad)
$grid.jqGrid('setGridParam', { datatype: "local", loadonce: false });
},
loadError: function(xhr, st, errorThrown) { // - todo: handle error from server during load, need to spruce this up
_initialDataLoad = false;
$('#fileUploadOK').hide();
ShowButtons(false, IsGridValid()); // - refresh button states if grid is loaded
$grid.jqGrid('setGridParam', { datatype: "local", loadonce: false }); // - fail, lets rebind an empty grid for manual entry
Toggle(true); // - slide toggle the top section open
},
loadComplete: function(data) {
$('#filterInvalid').prop('disabled', false);
$grid.jqGrid('hideCol', 'cb'); // - hide the check boxes for multi-select
if (_initialLoad) { // - set the column header tooltips on initial empty bind
setTooltipsOnColumnHeader($grid, 1, 'IDType (required)\nExample:\n1: International Passport\n2: National ID\n3: Drivers License\n4: Other ');
setTooltipsOnColumnHeader($grid, 2, 'IDNumber (required)\nIDNumber for corresponding IDType.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 3, 'LastName (required)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 4, 'FirstName (required)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 5, 'MiddleInitial (optional)\nMax length 40.');
setTooltipsOnColumnHeader($grid, 6, 'EmbossLine1 (optional)\nThis is the text to be embossed on the first line of the card. If it is blank, it will default to the FirstName LastName.\nMax length 19.');
setTooltipsOnColumnHeader($grid, 7, 'EmbossLine2 (optional)\nIf 2nd Line Embossing is needed, specify the value here with no more than 19 characters and inform GTP that 2nd line embossing is requested for the order. (Note: not all vendors are able to emboss line 2)\nMax length 19.');
setTooltipsOnColumnHeader($grid, 8, 'Address1 (required)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 9, 'Address2 (optional)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 10, 'Address3 (optional)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 11, 'City (required)\nMax length 50.');
setTooltipsOnColumnHeader($grid, 12, 'Country (required)\nSee CountryCodeList sheet for valid Country codes\nMax length 2.');
setTooltipsOnColumnHeader($grid, 13, 'State (required)\nSee StateCountryCodeList sheet for valid State/Country combinations.');
setTooltipsOnColumnHeader($grid, 14, 'PostalCode (optional)\nRequired for US addresses.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 15, 'DateOfBirth (required)\nMM/DD/YYY format.');
setTooltipsOnColumnHeader($grid, 16, 'EmailAddress (optional)\nMax length 100.');
setTooltipsOnColumnHeader($grid, 17, 'HomePhone (optional)\nPrefix with country code; no leading zeros.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 18, 'OfficePhone (optional)\nPrefix with country code; no leading zeros.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 19, 'MobilePhone (required)\nPrefix with country code; no leading zeros.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 20, 'Photo Reference (required for Photo Card orders.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 21, 'SalaryID (optional)\nCan be used for account or for picture id to map to a jpeg file.\nMax length 30.');
setTooltipsOnColumnHeader($grid, 22, 'SolID (required by some banks)\nFour digit value with leading zeros.');
setTooltipsOnColumnHeader($grid, 23, 'IDImage (optional)\nName of associated ID image file.');
_initialLoad = false;
} else
$('#txtCardCount').val($grid.getGridParam('records')); // - set the total card count
refreshIDImages();
if (_selectedConfiguration) {
ZapColumn($grid, 'SolID', _selectedConfiguration.MYISBRANCHIDREQ === 'N');
ZapColumn($grid, 'PhotoReference', !$('#cbPhotoID').prop('checked'));
}
if (_initialDataLoad) {
IsImageUploadValid();
$('#fileUploadOK').show(); // - display upload status
var setErrors = new GridErrors($grid);
setErrors.setEmboss = true;
setErrors.setPhotoReference = true;
setErrors.setSolID = true;
setErrors.execute();
}
var gridValid = IsGridValid();
ShowButtons(true, gridValid);
if (_initialDataLoad) {
ResetFilter(gridValid);
$grid.trigger('reloadGrid', [{ page: 1}]);
}
_initialDataLoad = false;
}
}).jqGrid('navGrid', '#pager', { refresh: false, search: false }, editSettings, addSettings, delSettings, {
multipleSearch: true,
overlay: false,
onClose: function(form) {
// if we close the search dialog while the datepicker is open
// the datepicker will stay opened. To fix this we have to hide
// the div used by datepicker
$('div#ui-datepicker-div.ui-datepicker').hide();
}
}).jqGrid('filterToolbar', {
stringResult: true,
searchOnEnter: false,
beforeSearch: function() { return false; }
}); //.jqGrid('setFrozenColumns'); // - this freezes columns during horiz. scrolling
}
This is the data (kind of, just showing an example of ErrorCells)
Any advice appreciated, thanks.
The problem seems to me independent from the used jQuery version. The reason of described problem is the usage of old style filter
$.extend(postdata, { // - set filter condition
filters: '',
searchField: 'ErrorCells',
searchOper: 'ne',
searchString: '0'
});
instead of new-style filter
$.extend(postdata, { // - set filter condition
filters: JSON.stringify({
groupOp: "AND",
groups: [],
rules: [{field: "ErrorCells", op: "ne", data: "0"}]
})
});
or
$.extend(postdata, { // - set filter condition
filters: {
groupOp: "AND",
groups: [],
rules: [{field: "ErrorCells", op: "ne", data: "0"}]
}
});
By the way you use multipleSearch: true
and the old style filter could not be displayed.
Nevertheless free jqGrid should in general work with old style filter too. I fixed the problem and posted the commit to GitHub. You need to download the latest sources from GitHub.
Thank you for reporting the bug!
Please verify that the problem is fixed with the latest sources, but after that I would recommend you to change the old-style filter to the new-style (see the code above).