Как сохранить текущую строку в jqgrid

Как определить текущую строку, если сетка открывается снова или страница обновляется?

Ответ в настройках сохраняемого столбца jqGrid описывает, как сохранить ширину столбца и некоторые другие параметры.

В этом ответе на демо я щелкнул в какой-то строке и нажал F5 . Предыдущая нажатая строка не была выделена. Как сохранить / восстановить текущую строку в локальном хранилище?

Обновить

Если в приложении изменяется структура столбца jqGrid, и пользователь снова открывает приложение из браузера, restorecolumnstate создает недопустимую colmodel, в которой отсутствуют некоторые элементы. Это вызывает исключение в refreshSearchingToolbar, которое предполагает наличие всех элементов colmodel.

Как это исправить? Как вычесть модифицированный колмодол и не восстановить колмодель в этом случае? Или должны восстановить ColumnState обновить colModel, чтобы создать правильный массив?

** Обновление 2 **

Если myColumnsState.permutation содержит нули $grid.jqGrid("remapColumns", myColumnsState.permutation, true) создал недействительный colmodel. Вот скриншоты из отладчика VS непосредственно до и после вызова remapColumns

после:

после

Я исправил это, изменив код на

    if (isColState && myColumnsState.permutation.length > 0) {
        var i, isnull = false;
        for (i = 0; i < myColumnsState.permutation.length; i = i + 1) {
            if (myColumnsState.permutation[i] == null) {
                isnull = true;
                break;
            }
        }
        if (!isnull) {
            $grid.jqGrid("remapColumns", myColumnsState.permutation, true);
        }

Это лучшее решение?

2 ответа

Решение

Я соединил код из предыдущего ответа о сохранении предпочтений столбца jqGrid с кодом из другого ответа, где я предложил код, в котором реализован постоянный выбор строк. Важно отметить, что в случае multiselect:true будет использоваться массив идентификаторов выбранных строк, который содержит все выбранные, даже если строки находятся на другой странице. Это очень практично, а реализация очень проста. Поэтому я разместил соответствующий запрос на добавление функции, но он до сих пор остается без ответа.

Теперь я могу представить два демо: первое демо, которое использует multiselect: true и вторая демонстрация, которая использует тот же код, но с одним выбором.

Наиболее важные части кода, который я использовал, вы найдете ниже.

Очень важно упомянуть одну вещь: вы должны изменить значение myColumnStateName на каждой странице, которую вы используете. Значение переменной содержит имя состояния столбца в localStorage, Так что если вы не измените имя, вы будете использовать состояние разных таблиц, что может привести к очень странным эффектам. Вы можете использовать имена, созданные на основе имени текущей страницы или ее URL, в качестве значения myColumnStateName,

var $grid = $("#list"),
    getColumnIndex = function (grid, columnIndex) {
        var cm = grid.jqGrid('getGridParam', 'colModel'), i, l = cm.length;
        for (i = 0; i < l; i++) {
            if ((cm[i].index || cm[i].name) === columnIndex) {
                return i; // return the colModel index
            }
        }
        return -1;
    },
    refreshSerchingToolbar = function ($grid, myDefaultSearch) {
        var postData = $grid.jqGrid('getGridParam', 'postData'), filters, i, l,
            rules, rule, iCol, cm = $grid.jqGrid('getGridParam', 'colModel'),
            cmi, control, tagName;

        for (i = 0, l = cm.length; i < l; i++) {
            control = $("#gs_" + $.jgrid.jqID(cm[i].name));
            if (control.length > 0) {
                tagName = control[0].tagName.toUpperCase();
                if (tagName === "SELECT") { // && cmi.stype === "select"
                    control.find("option[value='']")
                        .attr('selected', 'selected');
                } else if (tagName === "INPUT") {
                    control.val('');
                }
            }
        }

        if (typeof (postData.filters) === "string" &&
                typeof ($grid[0].ftoolbar) === "boolean" && $grid[0].ftoolbar) {

            filters = $.parseJSON(postData.filters);
            if (filters && filters.groupOp === "AND" && typeof (filters.groups) === "undefined") {
                // only in case of advance searching without grouping we import filters in the
                // searching toolbar
                rules = filters.rules;
                for (i = 0, l = rules.length; i < l; i++) {
                    rule = rules[i];
                    iCol = getColumnIndex($grid, rule.field);
                    if (iCol >= 0) {
                        cmi = cm[iCol];
                        control = $("#gs_" + $.jgrid.jqID(cmi.name));
                        if (control.length > 0 &&
                                (((typeof (cmi.searchoptions) === "undefined" ||
                                typeof (cmi.searchoptions.sopt) === "undefined")
                                && rule.op === myDefaultSearch) ||
                                  (typeof (cmi.searchoptions) === "object" &&
                                      $.isArray(cmi.searchoptions.sopt) &&
                                      cmi.searchoptions.sopt.length > 0 &&
                                      cmi.searchoptions.sopt[0] === rule.op))) {
                            tagName = control[0].tagName.toUpperCase();
                            if (tagName === "SELECT") { // && cmi.stype === "select"
                                control.find("option[value='" + $.jgrid.jqID(rule.data) + "']")
                                    .attr('selected', 'selected');
                            } else if (tagName === "INPUT") {
                                control.val(rule.data);
                            }
                        }
                    }
                }
            }
        }
    },
    saveObjectInLocalStorage = function (storageItemName, object) {
        if (typeof window.localStorage !== 'undefined') {
            window.localStorage.setItem(storageItemName, JSON.stringify(object));
        }
    },
    removeObjectFromLocalStorage = function (storageItemName) {
        if (typeof window.localStorage !== 'undefined') {
            window.localStorage.removeItem(storageItemName);
        }
    },
    getObjectFromLocalStorage = function (storageItemName) {
        if (typeof window.localStorage !== 'undefined') {
            return JSON.parse(window.localStorage.getItem(storageItemName));
        }
    },
    myColumnStateName = 'ColumnChooserAndLocalStorage2.colState',
    idsOfSelectedRows = [],
    saveColumnState = function (perm) {
        var colModel = this.jqGrid('getGridParam', 'colModel'), i, l = colModel.length, colItem, cmName,
            postData = this.jqGrid('getGridParam', 'postData'),
            columnsState = {
                search: this.jqGrid('getGridParam', 'search'),
                page: this.jqGrid('getGridParam', 'page'),
                sortname: this.jqGrid('getGridParam', 'sortname'),
                sortorder: this.jqGrid('getGridParam', 'sortorder'),
                permutation: perm,
                selectedRows: idsOfSelectedRows,
                colStates: {}
            },
            colStates = columnsState.colStates;

        if (typeof (postData.filters) !== 'undefined') {
            columnsState.filters = postData.filters;
        }

        for (i = 0; i < l; i++) {
            colItem = colModel[i];
            cmName = colItem.name;
            if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
                colStates[cmName] = {
                    width: colItem.width,
                    hidden: colItem.hidden
                };
            }
        }
        saveObjectInLocalStorage(myColumnStateName, columnsState);
    },
    myColumnsState,
    isColState,
    restoreColumnState = function (colModel) {
        var colItem, i, l = colModel.length, colStates, cmName,
            columnsState = getObjectFromLocalStorage(myColumnStateName);

        if (columnsState) {
            colStates = columnsState.colStates;
            for (i = 0; i < l; i++) {
                colItem = colModel[i];
                cmName = colItem.name;
                if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
                    colModel[i] = $.extend(true, {}, colModel[i], colStates[cmName]);
                }
            }
        }
        return columnsState;
    },
    updateIdsOfSelectedRows = function (id, isSelected) {
        var index = idsOfSelectedRows.indexOf(id);
        if (!isSelected && index >= 0) {
            idsOfSelectedRows.splice(index, 1); // remove id from the list
        } else if (index < 0) {
            idsOfSelectedRows.push(id);
        }
    },
    firstLoad = true;

myColumnsState = restoreColumnState(cm);
isColState = typeof (myColumnsState) !== 'undefined' && myColumnsState !== null;
idsOfSelectedRows = isColState && typeof (myColumnsState.selectedRows) !== "undefined" ? myColumnsState.selectedRows : [];

$grid.jqGrid({
    // ... some options
    page: isColState ? myColumnsState.page : 1,
    search: isColState ? myColumnsState.search : false,
    postData: isColState ? { filters: myColumnsState.filters } : {},
    sortname: isColState ? myColumnsState.sortname : 'invdate',
    sortorder: isColState ? myColumnsState.sortorder : 'desc',
    onSelectRow: function (id, isSelected) {
        updateIdsOfSelectedRows(id, isSelected);
        saveColumnState.call($grid, $grid[0].p.remapColumns);
    },
    onSelectAll: function (aRowids, isSelected) {
        var i, count, id;
        for (i = 0, count = aRowids.length; i < count; i++) {
            id = aRowids[i];
            updateIdsOfSelectedRows(id, isSelected);
        }
        saveColumnState.call($grid, $grid[0].p.remapColumns);
    },
    loadComplete: function () {
        var $this = $(this), i, count;

        if (firstLoad) {
            firstLoad = false;
            if (isColState) {
                $this.jqGrid("remapColumns", myColumnsState.permutation, true);
            }
            if (typeof (this.ftoolbar) !== "boolean" || !this.ftoolbar) {
                // create toolbar if needed
                $this.jqGrid('filterToolbar',
                    {stringResult: true, searchOnEnter: true, defaultSearch: myDefaultSearch});
            }
        }
        refreshSerchingToolbar($this, myDefaultSearch);
        for (i = 0, count = idsOfSelectedRows.length; i < count; i++) {
            $this.jqGrid('setSelection', idsOfSelectedRows[i], false);
        }
        saveColumnState.call($this, this.p.remapColumns);
    },
    resizeStop: function () {
        saveColumnState.call($grid, $grid[0].p.remapColumns);
    }
});

$grid.jqGrid('navGrid', '#pager', {edit: false, add: false, del: false});
$grid.jqGrid('navButtonAdd', '#pager', {
    caption: "",
    buttonicon: "ui-icon-closethick",
    title: "clear saved grid's settings",
    onClickButton: function () {
        removeObjectFromLocalStorage(myColumnStateName);
        window.location.reload();
    }
});

ОБНОВЛЕНО: я забыл упомянуть, что в случае использования multiselect: true В варианте с jqGrid 4.3 очень важно использовать исправление, описанное здесь. В первом демо я использовал модифицированную версию jquery.jqGrid.src.js которые включают исправление ошибки.

ОБНОВЛЕНО 2: Чтобы упростить создание уникального имени элемента локального хранилища, используемого для сохранения состояния сетки, я немного изменил демоверсии. Следующая версия демонстрации с множественным выбором и демонстрационное использование одного выбора myColumnStateName как функция, определенная следующим образом

var myColumnStateName = function (grid) {
        return window.location.pathname + '#' + grid[0].id;
    }

Использование myColumnStateName изменены соответственно. Кроме того, я расширил состояние столбца, чтобы сохранить rowNum значение.

ОБНОВЛЕНО 3: Ответ описывает, как можно использовать новую возможность бесплатной jqGrid для сохранения состояния сетки.

Решение Олега выдает ошибку при обновлении страницы, как показано ниже.

Ошибка: Uncaught TypeError: Невозможно прочитать свойство 'el' из неопределенного

Строка: 1936 в jquery.jqGrid.src.js

var previousSelectedTh = ts.grid.headers[ts.p.lastsort].el, newSelectedTh = ts.grid.headers[idxcol].el;

Решением этой проблемы является сохранение параметра сетки lastsort и сброс его после завершения загрузки, как показано ниже.

saveColumnState = function(perm) {
...
  columnsState = {
    search: this.jqGrid('getGridParam', 'search'),
    page: this.jqGrid('getGridParam', 'page'),
    sortname: this.jqGrid('getGridParam', 'sortname'),
    sortorder: this.jqGrid('getGridParam', 'sortorder'),
    lastsort: this.jqGrid('getGridParam', 'lastsort'),
    permutation: perm,
    colStates: { }
  },
...
},

loadComplete: function(data) {
...
  if (isColState) {
    $this.jqGrid("remapColumns", myColumnsState.permutation, true);
    if(myColumnsState.lastsort > -1)
      $this.jqGrid("setGridParam", { lastsort: myColumnsState.lastsort });
  }
...
},
Другие вопросы по тегам