简体   繁体   English

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

[英]ag-grid Infinite row model — Pre-caching of blocks

I'm using the ag-grid infinite row model and notice when I reach the end of a block, the fetch of the next block happens. 我正在使用ag-grid无限行模型,请注意,当我到达一个块的末尾时,就会发生下一个块的获取。 Is there a way I can trigger this fetch a number of rows before the user reaches scrolling to that point so the view looks more seamless? 有没有一种方法可以触发此操作以在用户到达滚动到该点之前获取许多行,从而使视图看起来更加无缝? eg pre-caching blocks before reaching the end of a block? 例如在到达块末尾之前预缓存块?

Yes this is possible. 是的,这是可能的。 We have implemented the same, although our main concern was not to prefetch rows but rather implement clean Redux with Ag-Grid-For-Angular. 我们已经实现了相同的方法,尽管我们的主要关注不是预取行,而是使用Ag-Grid-For-Angular实现干净的Redux。 It is hacky though, so you have been warned. 虽然它很hacky,所以已经警告您。 Also note that I have removed all the Angular-specific parts, so this solution should work with native JS/TS (with help of RXSJ) as well, in theory. 还要注意,我已经删除了所有特定于Angular的部分,因此,从理论上讲,该解决方案也应与本机JS / TS(在RXSJ的帮助下)一起使用。 But I have not tested it myself. 但是我自己还没有测试过。 Please report whether you had success or not. 请报告您是否成功。 Now let's get started: 现在开始吧:

In the gridOptions-object, you have the possibility to set: 在gridOptions对象中,可以设置:

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

But this is not doing what you think it does. 但这并没有按照您的想法做。 ViewportChangedEvent does not represent the block of currently visible elements on the screen but rather the last loaded block (with elements that might not be in viewport yet). ViewportChangedEvent并不代表屏幕上当前可见的元素的块,而是最后加载的块(其中的元素可能不在视口中)。 But you will still need this information to calculate the distance between what has been fetched and where you are on the screen right now. 但是,您仍将需要此信息来计算已获取内容与您当前在屏幕上的位置之间的距离。

For the second needed piece of information (eg where you are right now), you do have access to another method, but this is something I got from the AgGrid-Founder Niall Crosby's comment on GitHub, it is not in the official documentation and not in the Typescript-interface of AgGrid: 对于第二条所需的信息(例如,您现在的位置),您确实可以使用另一种方法,但这是我从AgGrid创始人Niall Crosby对GitHub的评论中获得的,它不在官方文档中,在AgGrid的Typescript界面​​中:

First you need to define a field 首先,您需要定义一个字段

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

Because the scrolling will happen many times a second you and want to use debounceTime to handle only a maximum number of scroll events. 因为滚动每秒会发生很多次,所以您想使用debounceTime仅处理最大数量的滚动事件。 Then you need to push the actual viewport-events into the Observable/Subject. 然后,您需要将实际的视口事件推送到Observable / Subject中。 So after defining gridOptions, do: 因此,在定义gridOptions之后,请执行以下操作:

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

Since as I mentioned, onBodyScroll is not officially documented, it is also not in the GridOptions interface, this is why I do the cast as any 如前所述,由于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
  });

Now, having both the reference to the last fetched block as well as the last visible item you can control the requests yourself. 现在,有了对最后一个获取的块的引用以及最后一个可见项,您就可以自己控制请求。 Just set the distance between those two parameters and call your httpClient and update the array of your items. 只需设置这两个参数之间的距离,然后调用httpClient并更新项目数组即可。 The only thing left now is to set the fetched items in the grid-model: 现在剩下的唯一事情是在网格模型中设置获取的项目:

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

Note that _totalCount is the maximum number of rows you can get for a chunked request. 请注意, _totalCount是您可以为分块请求获得的最大行数。 You get this information from your backend-query, for example Lucene/ElasticSearch. 您可以从后端查询中获取此信息,例如Lucene / ElasticSearch。 You can also set limit to -1, in which case you can always scroll down, but the rows will never be loaded. 您还可以将limit设置为-1,在这种情况下,您始终可以向下滚动,但永远不会加载行。

Also note that when fetching things by yourself, the first block needs to be fetched manually because this._onAgGridBodyScroll$ will only get triggered and cause subsequent fetches if there is some data in the viewport already. 还要注意,当自己获取内容时,需要手动获取第一个块,因为this._onAgGridBodyScroll$仅在视口中已经有数据的情况下才会被触发并引起后续的获取。 This is the Angular-specific part that I mentioned (in Angular you would do this in the initialization-lifecycle-hook "OnInit"). 这是我提到的特定于Angular的部分(在Angular中,您可以在初始化生命周期钩子“ OnInit”中执行此操作)。

That's it! 而已! Hope it helps. 希望能帮助到你。 Actually I am working on a blog article about this with pictures and stuff; 实际上,我正在写一篇有关图片和内容的博客文章。 I will add a link here when it's finished. 完成后,我将在此处添加一个链接。 If you have any suggestions, please comment. 如果您有任何建议,请发表评论。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM