免费 jqGrid:使用本地数据扩展 postdata 时出现字段未定义错误

Free jqGrid: Field undefined error when extending postdata with local data

我一直在将我的项目升级到 jQuery 1.12.0 和最新版本的免费 jqGrid。我现在在 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;
};

匹配字符串如下所示:

(String(ErrorCells).toUpperCase() !== String("0").toUpperCase())

我正在过滤掉有错误的行(ErrorCells 用作位域),但看起来需要明确的 this.ErrorCells。在不修改 jqGrid 源代码的情况下,我无法理解到底发生了什么变化以及是否有解决方案。

**** 更新 ****

下面你可以看到在 $.each 处理程序中,ErrorCells 是未定义的,但是 this.ErrorCells 是。

这是使用过滤条件扩展 postdata 的代码:

$.extend(postdata, { // - set filter condition
    filters: '',
    searchField: 'ErrorCells',
    searchOper: 'ne',
    searchString: '0'
});

$grid.jqGrid('setGridParam', { search: true, postData: postdata });
$grid.trigger('reloadGrid', [{ page: 1}]);      

这是网格配置:

$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: "&nbsp;" },
            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: "&nbsp;" },
            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: "&nbsp;" },
            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 ? '*' : '&nbsp;');
                        $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 ? '*' : '&nbsp;');
                    } 
                    },
                    { 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'>&nbsp;</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: "&nbsp;" },
            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: "&nbsp;" },
            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: "&nbsp;" },
            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: "&nbsp;" },
            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: "&nbsp;" },
            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

}

这是数据(某种程度上,只是展示了 ErrorCells 的一个例子)

感谢任何建议,谢谢。

这个问题在我看来与使用的 jQuery 版本无关。所述问题的原因是使用旧式过滤器

$.extend(postdata, { // - set filter condition
    filters: '',
    searchField: 'ErrorCells',
    searchOper: 'ne',
    searchString: '0'
});

代替new-style过滤器

$.extend(postdata, { // - set filter condition
    filters: JSON.stringify({
        groupOp: "AND",
        groups: [],
        rules: [{field: "ErrorCells", op: "ne", data: "0"}]
    })
});

$.extend(postdata, { // - set filter condition
    filters: {
        groupOp: "AND",
        groups: [],
        rules: [{field: "ErrorCells", op: "ne", data: "0"}]
    }
});

顺便问一下,您使用的方式multipleSearch: true,旧样式的过滤器无法显示。

尽管如此,免费的 jqGrid 通常也应该与旧式过滤器一起使用。我解决了问题并将 the commit 发布到 GitHub。您需要从 GitHub.

下载最新的资源

感谢您报告错误!

请确认问题已通过最新源解决,但之后我建议您将 old-style 过滤器更改为 new-style(参见上面的代码)。