SlickGrid:如何在分页网格中保留选定的行?

发布于 2024-11-25 09:55:34 字数 382 浏览 3 评论 0原文

我将 SlickGrid 的分页版本与 CheckboxSelection-Plugin 结合使用。不幸的是,当用户离开当前网格页面时,行选择会丢失,并且在再次访问该页面时不会恢复。此行为也可以通过 SlickGrid 示例 #4 重现。 (单击网格页脚中的小灯泡图标以打开分页)

我已将此情况告知 SlickGrid 的作者,但他并不认为此行为是一个错误,因为 SlickGrid 更像是一个网格框架,而不仅仅是 -添加数据解决方案。

有谁知道如何在 SlickGrid 中实现可靠的选择持久性,该方法适用于分页和非分页网格?

I'm using a paginated version of SlickGrid in conjunction with the CheckboxSelection-Plugin. Unfortunately, the row selection gets lost when one leaves the current grid page and isn't restored when that page is accessed again. This behaviour can also be reproduced with SlickGrid example #4. (click the little light-bulb-icon in the grid footer to turn on pagination)

I've informed SlickGrid's author about this, but he doesn't see this behaviour as a bug, as SlickGrid is more a grid framework than a just-add-data-solution.

Does anyone have an idea on how to implement reliable selection persistence in SlickGrid, that works for both paginated and non-paginated grids?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ヤ经典坏疍 2024-12-02 09:55:34

最后,我通过调整示例 4 中的 grid.onSelectedRowsChanged 回调取得了一些成功。主要区别在于,每次选择更改时我不会重置全局 selectedRowIds 数组,因为 grid.getSelectedRows () 只提供当前页面上选定的行索引。相反,我首先将所有新选择的行添加到 selectedRowIds 数组中,然后对其进行迭代以检查其当前页面条目之一是否已被取消选择。

grid.onSelectedRowsChanged.subscribe(function (e) {
    var selRows = grid.getSelectedRows();
    // add all newly selected rows to the selection
    for (var i = 0, l = selRows.length; i < l; i++) {
        var item = dataView.getItem(selRows[i]);
        if (item) {
            var rowId = item.id;
            if (selectedRowIds.indexOf(rowId) < 0) {
                selectedRowIds.push(rowId);
            }
        }
    }

    //check if a previously selected row has been deselected
    for (var i = 0, l = selectedRowIds.length; i < l; i++) {
        var row = dataView.getRowById(selectedRowIds[i]); // see if the selected row is   available on the current page
        if (row && selRows.indexOf(row) < 0) {
            selectedRowIds.splice(i, 1); //remove row from array
        }
    }
   });

Finally I had some success by adapting the grid.onSelectedRowsChanged callback in Example 4. The key difference is that I don't reset the global selectedRowIds array each time the selection changes, since grid.getSelectedRows() only gives me the selected row indices on the current page. Instead I first add all newly selected rows to the selectedRowIds array and then iterate over it to check if one of its current-page-entries has been deselected.

grid.onSelectedRowsChanged.subscribe(function (e) {
    var selRows = grid.getSelectedRows();
    // add all newly selected rows to the selection
    for (var i = 0, l = selRows.length; i < l; i++) {
        var item = dataView.getItem(selRows[i]);
        if (item) {
            var rowId = item.id;
            if (selectedRowIds.indexOf(rowId) < 0) {
                selectedRowIds.push(rowId);
            }
        }
    }

    //check if a previously selected row has been deselected
    for (var i = 0, l = selectedRowIds.length; i < l; i++) {
        var row = dataView.getRowById(selectedRowIds[i]); // see if the selected row is   available on the current page
        if (row && selRows.indexOf(row) < 0) {
            selectedRowIds.splice(i, 1); //remove row from array
        }
    }
   });
面如桃花 2024-12-02 09:55:34

我知道这是一个老问题,但我必须实现这个问题,并且建议的解决方案并未涵盖所有用例(例如,如果用户转到最后一页而不进行任何选择,@fbuchinger 提出的解决方案会删除一些选择,并且返回第一页)。

为了解决这个问题,我必须做一个更复杂的实现,我什至必须添加一个新的 DataView 事件 onBeforePagingInfoChanged 并修改 SlickGrid 事件 onSelectedRowsChanged 以返回上一行选择(在当前选择之上)。这些更改是在 6pac/SlickGrid 分支中进行的,并在版本 2.4.18 下发布

我在使用分页时使用的步骤如下,我们不能只使用 getSelectedRows() 因为这只会返回当前页面中的选择,这是不够的,我们需要保持具有数据对象 ID 的全局数组(不是行索引,因为它会在页面中不断变化),为了同时保留网格索引和数据 ID,我们将在 dataView.mapIdsToRows() 之间交替和dataView.mapRowsToIds()。

下面显示的代码步骤如下:

  1. 更改行选择时,如果新选择尚未位于所选 ID 的全局数组中,我们将添加新选择;
  2. 删除行选择时,我们将从全局数组中删除该选择 在我们更改页面之前,我们将跟踪所选 ID 的数量(除非它来自页面更改)
  3. 跟踪一个标志(该标志将用于在我们更改页面时跳过任何删除)
  4. ,我们将在页面更改后 ,我们'我会进行额外的(和延迟的)检查以确保我们在选定 ID 的全局数组中显示的内容将显示在屏幕上。
// global variables
_selectedRowDataContextIds = [];     // used with row selection
_wasRecheckedAfterPageChange = true; // used with row selection & pagination

function bindSlickgridEventsForRowSelectionWithPagination() {
this._eventHandler.subscribe(this._dataView.onBeforePagingInfoChanged, () => {
        this._wasRecheckedAfterPageChange = false; // reset the page check flag, to skip deletions on page change (used in code below)
      });

      this._eventHandler.subscribe(this._dataView.onPagingInfoChanged, () => {
        // when user changes page, the selected row indexes might not show up
        // we can check to make sure it is but it has to be in a delay so it happens after the first "onSelectedRowsChanged" is triggered
        setTimeout(() => {
          const shouldBeSelectedRowIndexes = this._dataView.mapIdsToRows(this._selectedRowDataContextIds);
          const currentSelectedRowIndexes = this._grid.getSelectedRows();
          if (!isequal(shouldBeSelectedRowIndexes, currentSelectedRowIndexes)) {
            this._grid.setSelectedRows(shouldBeSelectedRowIndexes);
          }
        });
      });

      this._eventHandler.subscribe(this._grid.onSelectedRowsChanged, (e, args) => {
        if (Array.isArray(args.rows) && Array.isArray(args.previousSelectedRows)) {
          const newSelectedRows = args.rows;
          const prevSelectedRows = args.previousSelectedRows;

          const newSelectAdditions = newSelectedRows.filter((i) => prevSelectedRows.indexOf(i) < 0);
          const newSelectDeletions = prevSelectedRows.filter((i) => newSelectedRows.indexOf(i) < 0);

          // deletion might happen when user is changing page, if that is the case then skip the deletion since it's only a visual deletion
          // if it's not a page change (when the flag is true), then proceed with the deletion in our global array of selected IDs
          if (this._wasRecheckedAfterPageChange && newSelectDeletions.length > 0) {
            const toDeleteDataIds = this._dataView.mapRowsToIds(newSelectDeletions);
            toDeleteDataIds.forEach((removeId) => this._selectedRowDataContextIds.splice(this._selectedRowDataContextIds.indexOf(removeId), 1));
          }

          // if we have newly added selected row(s), let's update our global array of selected IDs
          if (newSelectAdditions.length > 0) {
            const toAddDataIds = this._dataView.mapRowsToIds(newSelectAdditions) || [];
            toAddDataIds.forEach((dataId) => {
              if (this._selectedRowDataContextIds.indexOf(dataId) === -1) {
                this._selectedRowDataContextIds.push(dataId);
              }
            });
          }
          this._wasRecheckedAfterPageChange = true;

          // form our full selected row IDs, let's make sure these indexes are selected in the grid, if not then let's call a reselect
          // this could happen if the previous step was a page change
          const shouldBeSelectedRowIndexes = this._dataView.mapIdsToRows(this._selectedRowDataContextIds);
          const currentSelectedRowIndexes = this._grid.getSelectedRows();
          if (!isequal(shouldBeSelectedRowIndexes, currentSelectedRowIndexes)) {
            this._grid.setSelectedRows(shouldBeSelectedRowIndexes);
          }


          const newSelections = { gridRowIndexes: this._grid.getSelectedRows(), dataContextIds: this._selectedRowDataContextIds };
        }
      });
}

因此,在此代码中,变量 this._selectedRowDataContextIds 具有完整的选定数据对象 ID 集。这是一种复杂的方法,但这就是我迄今为止发现的使用网格分页的方法。

请注意,代码中仅使用 1 个 lodash 函数 isequal 来比较 2 个数组,其他所有内容都是用 ES6 和 TypeScript 编写的(尽管我删除了更多类型)可读)

I know this is an old question but I had to implement this and the proposed solution didn't cover all use case (for example, the proposed solution by @fbuchinger removes some selection if user goes to last page, without doing any selections, and comes back to first page).

To deal with this issue, I had to do a much more complex implementation and I even had to add a new DataView event onBeforePagingInfoChanged and also modified the SlickGrid event onSelectedRowsChanged to also return previous row selections (on top of current selections). These changes were made in the 6pac/SlickGrid fork and were released under version 2.4.18

The steps I used are the following when using Pagination, we can't just use the getSelectedRows() since this will only return the selection in current page which is not enough, we need to keep a global array with data object IDs (not the row indexes since that will keep changing in a page), to keep both the grid indexes and the data IDs, we'll alternate between dataView.mapIdsToRows() and dataView.mapRowsToIds().

The steps of the code shown below are the following

  1. when changing a row selection, we'll add the new selection if it's not yet in the global array of selected IDs
  2. when deleting a row selection, we'll remove the selection from our global array of selected IDs (unless it came from a page change)
  3. before we change page, we'll keep track with a flag (this flag will be used to skip any deletion when we're changing page)
  4. after the page is changed, we'll do an extra (and delayed) check to make sure that what we have in our global array of selected IDs is displayed on screen
// global variables
_selectedRowDataContextIds = [];     // used with row selection
_wasRecheckedAfterPageChange = true; // used with row selection & pagination

function bindSlickgridEventsForRowSelectionWithPagination() {
this._eventHandler.subscribe(this._dataView.onBeforePagingInfoChanged, () => {
        this._wasRecheckedAfterPageChange = false; // reset the page check flag, to skip deletions on page change (used in code below)
      });

      this._eventHandler.subscribe(this._dataView.onPagingInfoChanged, () => {
        // when user changes page, the selected row indexes might not show up
        // we can check to make sure it is but it has to be in a delay so it happens after the first "onSelectedRowsChanged" is triggered
        setTimeout(() => {
          const shouldBeSelectedRowIndexes = this._dataView.mapIdsToRows(this._selectedRowDataContextIds);
          const currentSelectedRowIndexes = this._grid.getSelectedRows();
          if (!isequal(shouldBeSelectedRowIndexes, currentSelectedRowIndexes)) {
            this._grid.setSelectedRows(shouldBeSelectedRowIndexes);
          }
        });
      });

      this._eventHandler.subscribe(this._grid.onSelectedRowsChanged, (e, args) => {
        if (Array.isArray(args.rows) && Array.isArray(args.previousSelectedRows)) {
          const newSelectedRows = args.rows;
          const prevSelectedRows = args.previousSelectedRows;

          const newSelectAdditions = newSelectedRows.filter((i) => prevSelectedRows.indexOf(i) < 0);
          const newSelectDeletions = prevSelectedRows.filter((i) => newSelectedRows.indexOf(i) < 0);

          // deletion might happen when user is changing page, if that is the case then skip the deletion since it's only a visual deletion
          // if it's not a page change (when the flag is true), then proceed with the deletion in our global array of selected IDs
          if (this._wasRecheckedAfterPageChange && newSelectDeletions.length > 0) {
            const toDeleteDataIds = this._dataView.mapRowsToIds(newSelectDeletions);
            toDeleteDataIds.forEach((removeId) => this._selectedRowDataContextIds.splice(this._selectedRowDataContextIds.indexOf(removeId), 1));
          }

          // if we have newly added selected row(s), let's update our global array of selected IDs
          if (newSelectAdditions.length > 0) {
            const toAddDataIds = this._dataView.mapRowsToIds(newSelectAdditions) || [];
            toAddDataIds.forEach((dataId) => {
              if (this._selectedRowDataContextIds.indexOf(dataId) === -1) {
                this._selectedRowDataContextIds.push(dataId);
              }
            });
          }
          this._wasRecheckedAfterPageChange = true;

          // form our full selected row IDs, let's make sure these indexes are selected in the grid, if not then let's call a reselect
          // this could happen if the previous step was a page change
          const shouldBeSelectedRowIndexes = this._dataView.mapIdsToRows(this._selectedRowDataContextIds);
          const currentSelectedRowIndexes = this._grid.getSelectedRows();
          if (!isequal(shouldBeSelectedRowIndexes, currentSelectedRowIndexes)) {
            this._grid.setSelectedRows(shouldBeSelectedRowIndexes);
          }


          const newSelections = { gridRowIndexes: this._grid.getSelectedRows(), dataContextIds: this._selectedRowDataContextIds };
        }
      });
}

So in this code, the variable this._selectedRowDataContextIds has the full set of selected data object IDs. It's a complex approach but that is what I found so far to be working with a grid Pagination.

Note that there's only 1 lodash function isequal that is used in the code to compare 2 arrays, everything else is written in ES6 and TypeScript (though I removed the types to be more readable)

旧伤慢歌 2024-12-02 09:55:34

建议:

  1. 在网格定义之前添加行数组。

    var selectedRows = [];
    
  2. 在分页事件中,如果行尚未在数组中,则在所有获取和存储所选行之前:

    function AddRows(grid.getSelectedRows()){//您的比较在这里};
    
  3. 在分页事件中设置所选行:

    grid.setSelectedRows(selectedRows); 
    
  4. 防止取消选择。如果取消选择某行,则获取数组中的行索引,并从数组中删除该行:

    函数 GetRowSelectedIndex(row);
    var rowIndex = GetRowSelectedIndex(行);
    selectedRows.slice(rowIndex,1);
    

Proposal:

  1. Add an array of rows before grid definition.

    var selectedRows = [];
    
  2. In the pagging event, before all obtain and store selected rows if the row aren't in array yet:

    function AddRows(grid.getSelectedRows()){//your comparision here};
    
  3. In paggin event set selected rows:

    grid.setSelectedRows(selectedRows ); 
    
  4. Prevent deselect. If a row is deselect, get the row index in array, and remove the row from array:

    function GetRowSelectedIndex(row);
    var rowIndex = GetRowSelectedIndex(row);
    selectedRows.slice(rowIndex,1);
    
活雷疯 2024-12-02 09:55:34

效果很好。刚刚修改了上面的。

                var selRows = grid.getSelectedRows();
                var item = {};
                for (var i = 0; i < selRows.length; i++) {
                    item = dataView.getItem(selRows[i]);
                    if (item != undefined && $.inArray(item.id, selectedRowIds) < 0 ) {
                        selectedRowIds.push(item.id);
                    }
                }
                var removeIds = [];
                var row;
                for (var i = 0; i < selectedRowIds.length; i++) {
                    for (var j = 0; j < selectedRowIds.length; j++) {
                        row = dataView.getRowById(selectedRowIds[j]);
                        if(row != undefined && $.inArray(row, removeIds) < 0){
                            removeIds.push(row);
                            break;
                        }
                    }
                }
                for (var i = 0; i < removeIds.length; i++) {
                    if (removeIds[i] != undefined && $.inArray(removeIds[i], selRows) < 0) {
                        item = dataView.getItem(removeIds[i]);
                        selectedRowIds = $.grep(selectedRowIds, function( a ) { return a !== item.id; });
                    }
                }

it works fine. Just modified the above one.

                var selRows = grid.getSelectedRows();
                var item = {};
                for (var i = 0; i < selRows.length; i++) {
                    item = dataView.getItem(selRows[i]);
                    if (item != undefined && $.inArray(item.id, selectedRowIds) < 0 ) {
                        selectedRowIds.push(item.id);
                    }
                }
                var removeIds = [];
                var row;
                for (var i = 0; i < selectedRowIds.length; i++) {
                    for (var j = 0; j < selectedRowIds.length; j++) {
                        row = dataView.getRowById(selectedRowIds[j]);
                        if(row != undefined && $.inArray(row, removeIds) < 0){
                            removeIds.push(row);
                            break;
                        }
                    }
                }
                for (var i = 0; i < removeIds.length; i++) {
                    if (removeIds[i] != undefined && $.inArray(removeIds[i], selRows) < 0) {
                        item = dataView.getItem(removeIds[i]);
                        selectedRowIds = $.grep(selectedRowIds, function( a ) { return a !== item.id; });
                    }
                }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文