Бесплатная jqGrid: ошибка поля undefined при расширении постданных локальными данными

Я обновляю свои проекты до jQuery 1.12.0 и последней версии бесплатного jqGrid. Я сейчас вижу здесь, в jquery.jqGrid.src.js, ошибку поля undefined:

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)  введите описание изображения здесь

Любые советы приветствуются, спасибо.


person Rich T.    schedule 12.01.2016    source источник
comment
Не могли бы вы предоставить демонстрацию, которую можно использовать для воспроизведения проблемы? Невозможно решить проблему, не имея точного colModel, тестовых данных и тестового примера (пошаговая инструкция по воспроизведению проблемы). Мои старые демоверсии, которые я пробовал, не имеют проблем с jQuery 1.12.0.   -  person Oleg    schedule 12.01.2016
comment
Напишите короткий комментарий с @Oleg, чтобы сообщить мне, что вы внесли изменения в текст своего вопроса. Постараюсь воспроизвести проблему и скоро напишу свой ответ.   -  person Oleg    schedule 12.01.2016
comment
Хорошо, Олег, спасибо, я ценю это.   -  person Rich T.    schedule 12.01.2016


Ответы (1)


Мне кажется, что проблема не связана с используемой версией jQuery. Причина описанной проблемы - использование фильтра старого образца.

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

вместо фильтра нового стиля

$.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"}]
    }
});

Кстати, вы используете multipleSearch: true, и фильтр старого стиля не может быть отображен.

Тем не менее, бесплатный jqGrid должен работать и со старым фильтром. Я исправил проблему и опубликовал фиксацию на GitHub. Вам необходимо скачать последние исходные коды с GitHub.

Спасибо, что сообщили об ошибке!

Убедитесь, что проблема решена с использованием последних исходных кодов, но после этого я бы порекомендовал вам изменить фильтр старого стиля на фильтр нового стиля (см. Код выше).

person Oleg    schedule 12.01.2016
comment
Отлично, я проверю, спасибо за ваше время и усилия! - person Rich T.; 12.01.2016
comment
Я проверил, что новая сборка работает, я изменю, чтобы использовать новый стиль фильтра, как вы предлагаете. - person Rich T.; 12.01.2016
comment
@RichT .: Добро пожаловать! Кстати, вы можете подумать об удалении скрытых столбцов и перемещении туда в additionalProperties. Самым простым способом вы можете просто удалить столбцы и использовать вместо них additionalProperties: ["ErrorCells", "ErrorDescriptions"]. Информация будет храниться в локальных данных, в средствах форматирования, cellattr и так далее, но никто не создает <td> в DOM. additionalProperties может содержать строки или такие же структуры, как colModel. См. В качестве примера демонстрацию. - person Oleg; 13.01.2016