ag-grid无限行模型 - 块的预缓存

时间:2018-05-25 16:14:30

标签: javascript ag-grid

我正在使用ag-grid无限行模型,并注意到当到达块的末尾时,会发生下一个块的获取。有没有一种方法可以在用户滚动到该点之前触发此行获取多行,以便视图看起来更加无缝?例如在到达块结束之前预先缓存块?

1 个答案:

答案 0 :(得分:0)

是的,这是可能的。我们已经实现了相同的功能,尽管我们主要关注的不是预取行,而是使用Ag-Grid-For-Angular实现干净的Redux。虽然这很hacky,所以你被警告了。另请注意,我已删除了所有Angular特定的部分,因此理论上此解决方案也应该与原生JS / TS(在RXSJ的帮助下)一起使用。但我自己没有测试过。请报告您是否成功。现在让我们开始吧:

在gridOptions-object中,您可以设置:

onViewportChanged: (event: ViewportChangedEvent) => {
    // here you have access to event.firstRow and event.lastRow
    // On initialization, firstRow is 0 and lastRow -1
}

但这不符合你的想法。 ViewportChangedEvent不代表屏幕上当前可见元素的块,而是最后加载的块(具有可能尚未在视口中的元素)。但是,您仍然需要此信息来计算所提取内容与您现在在屏幕上的位置之间的距离。

对于第二个需要的信息(例如你现在的位置),你可以访问另一种方法,但这是我从AgGrid-Founder Niall Crosby对GitHub的评论得到的,它不在官方文档而不是AgGrid的Typescript接口:

首先,您需要定义一个字段

private _onAgGridBodyScroll$ = new Subject<BodyScrollEvent>();

因为滚动会每秒发生多次,并且想要使用debounceTime来处理最大数量的滚动事件。然后,您需要将实际的视口事件推送到Observable / Subject中。所以在定义gridOptions之后,执行:

(this.gridOptions as any).onBodyScroll = ((bodyScrollEvent: BodyScrollEvent) =>
    this._onAgGridBodyScroll$.next(bodyScrollEvent));

因为正如我所提到的,onBodyScroll没有正式记录,它也不在GridOptions界面中,这就是为什么我要进行投射as any

this._onAgGridBodyScroll$
  .takeUntil(this._destroy$)
  .debounceTime(200)
  .subscribe(() => {
    const allRows: HTMLElement[] = this._hostEl.nativeElement.getElementsByClassName('ag-row');
    if (allRows.length < 1) {
      return;
    }
    // aggrids viewport-rows can be inserted in a wrong/random order in the DOM, but they always have the right index-attribute:
    let biggestIndexInViewport: number = Number(allRows[0].getAttribute('row-index'));
    for (let i = 1; i < allRows.length; i++) {
      const itemIndexByAttr: number = Number(allRows[i].getAttribute('row-index'));
      if (itemIndexByAttr > biggestIndexInViewport) {
        biggestIndexInViewport = itemIndexByAttr;
      }
    }
    // so now you have the reference to the last visible row
    // note that by flipping the > you can also find out the first visible row
    // so when you destroy aggrid and reinitialize it again
    // with all the fetched items you have in your redux-store, 
    // you can scroll-to-top to the same row where you have been before
  });

现在,同时拥有对最后一个提取块的引用以及最后一个可见项,您可以自己控制请求。只需设置这两个参数之间的距离,然后调用httpClient并更新项目数组。现在唯一剩下的就是在网格模型中设置获取的项目:

  // do this in onGridReady():
  this.gridOptions.api.setDatasource({
    rowCount: null, // behave as infinite scroll
    getRows: (params: IGetRowsParams) => this.onGetRows(params)
  } as IDatasource);

  // and define:
  private onGetRows(params: IGetRowsParams): void {
    this.artikelArray$
      .takeUntil(this._destroy$)
      .filter((myItems: MyItems[]) => (!!myItems[params.startRow]))
      // do not check for endrow because request is always of static size, but response might be smaller
      .take(1) // unsubscribe after first handled value
      .subscribe(rowsToDisplay => {
        const limit: number = params.endRow >= this._totalCount ? this._totalCount : -1; // the smaller limit or none at all
        // in case you have new information concerning maximum size:
        params.successCallback(rowsToDisplay, limit);
      });
  }

请注意,_totalCount是分块请求可以获得的最大行数。您从后端查询中获取此信息,例如Lucene / ElasticSearch。您还可以将limit设置为-1,在这种情况下,您始终可以向下滚动,但永远不会加载行。

另请注意,在自己提取内容时,需要手动获取第一个块,因为this._onAgGridBodyScroll$只会被触发,并且如果视口中已存在某些数据,则会导致后续提取。这是我提到的Angular特定部分(在Angular中你会在initial-lifecycle-hook“OnInit”中执行此操作)。

就是这样!希望能帮助到你。实际上我正在撰写一篇关于图片和内容的博客文章。完成后我会在这里添加一个链接。如果您有任何建议,请发表评论。