【问题标题】:SlickGrid: How to keep selected rows in paginated grids?SlickGrid:如何将选定的行保留在分页网格中?
【发布时间】:2011-10-09 12:04:08
【问题描述】:

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

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

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

【问题讨论】:

    标签: jquery selection slickgrid


    【解决方案1】:

    建议:

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

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

      function AddRows(grid.getSelectedRows()){//your comparision here};
      
    3. 在分页事件中设置选定的行:

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

      function GetRowSelectedIndex(row);
      var rowIndex = GetRowSelectedIndex(row);
      selectedRows.slice(rowIndex,1);
      

    【讨论】:

    • 感谢 Alberto,但很遗憾,由于 SlickGrid 的一些缺陷,我无法使用您的建议:1)没有 onBeforePageChange 事件,当网格已经设置为新页面时调用 onPagingInfoChanged 2 ) 所有选定的行索引都相对于当前页面,因此使用行 ID 更可靠(请参阅下面的示例)。
    • 我同意你的看法。但是对于好奇者和测试者。你可以在 slick.grid.js PUBLIC API 中添加一个新事件来做这些事情。
    【解决方案2】:

    最后,通过在示例 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
            }
        }
       });
    

    【讨论】:

    • 高质量的解决方案!在我的建议中,我认为在 slickgrid 空间之外的数组中,这是在 DOM 空间中。但我认为您的解决方案很明确,并且可以重复使用很多
    【解决方案3】:

    它工作正常。刚刚修改了上面的那个。

                    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; });
                        }
                    }
    

    【讨论】:

    • 始终提供解释以及您的答案。
    【解决方案4】:

    我知道这是一个老问题,但我必须实施这个问题,并且建议的解决方案并未涵盖所有用例(例如,@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 编写的(尽管我删除了这些类型以提高可读性)

    【讨论】:

      猜你喜欢
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-23
      • 2013-08-02
      相关资源
      最近更新 更多