angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.34k stars 6.74k forks source link

infinite scroll for material table (cdk table) #9858

Closed TripleMap closed 6 years ago

TripleMap commented 6 years ago

feature request:

Does anybody implements infinite scroll to material/cdk table?

What is the expected behavior?

infinite scroll

What is the current behavior?

just update on data change event.

What is the use-case or motivation for changing an existing behavior?

I have more than 10 000 rows. Of course I can use pagination, but it will be much more representative and useful without paginator.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

angular 5.0.0 material 5.2.0

I have tried to add some new logic to table method renderRows(). It render some rows at specific place by currentIndex. But it looks like big crutch =(

andrewseguin commented 6 years ago

Here's a primitive and inefficient prototype that you can use to learn more about how to create an infinite list of rows:

https://stackblitz.com/edit/angular-1vg9gn?file=app/table-basic-example.ts

On the scroll event, see if the user is seeing a row within 200px of the bottom of the table. If so, add more data to the table's data source.

First step in optimizing this would be to debounce the scroll events since doing this calculation on every scroll event will bog down performance.

naveedahmed1 commented 6 years ago

@andrewseguin thanks for sharing this. I am trying the same solution with cdk-virtual-scroll and its working perfectly. Now I am trying incorporate the optimization tip you mentioned above and have below code:

      fromEvent(this.virtualViewport.nativeElement, 'scroll')
         .pipe(debounceTime(1000))
         .subscribe((e: any) => this.onScroll(e));
   }

But it doesn't seem to work and throw below error:

ERROR TypeError: Invalid event target
    at setupSubscription (fromEvent.js:50)
    at Observable._subscribe (fromEvent.js:24)
TheHanna commented 6 years ago

@TripleMap I built upon @andrewseguin's solution, creating a container that throttles and emits a scroll event while there is more data to load:

https://stackblitz.com/edit/angular-material-data-table-infinite-scroll

I'm using lodash to throttle the scroll event and dynamically assigning a scroll handler to either the host element or the window, based on the element's clientHeight/scrollHeight. This solution works for my use cases, YMMV

jacob-8 commented 6 years ago

@naveedahmed1 Would you mind posting a link to your cdk-virtual-scroll + material table solution? I'd love to use both of those together as well!

naveedahmed1 commented 6 years ago

@jacobbowdoin please take a look at: https://stackblitz.com/edit/angular-1vg9gn?file=app%2Ftable-basic-example.ts

Something similar to this should help:

<cdk-virtual-scroll-viewport itemSize="50" (scroll)="onScroll($event)" id="list">
  <div *cdkVirtualFor="let item of list; let index = index">

</cdk-virtual-scroll-viewport>
onScroll(e) {
    const tableViewHeight = e.target.offsetHeight // viewport: ~500px
    const tableScrollHeight = e.target.scrollHeight // length of all table
    const scrollLocation = e.target.scrollTop; // how far user scrolled

    // If the user has scrolled within 200px of the bottom, add more data
    const buffer = 200;
    const limit = tableScrollHeight - tableViewHeight - buffer;
    if (scrollLocation > limit) {
      this.dataSource = this.dataSource.concat(ELEMENT_DATA);
    }
  }
Hintalo commented 5 years ago

@naveedahmed1 I know it is a bit late, but maybe this helps you. I've tried the recommended optimization (using debounceTime() at the event subscription) with a mat-table element and it works for me. It is important to setup the subscription in the ngAfterViewInit() method, and that you use the "{read: ElementRef}" option at the @ViewChild-decorated class-variable (that points to the physical table element), i.e. @ViewChild('table', {read: ElementRef}) public matTableRef: ElementRef;

See my demo here: https://stackblitz.com/edit/mat-table-infinite-scroll

Note: this snipplet demonstrates a very simple bidirectional infinite-scrolling, with a simple memory-preserving array storage, At scrolling, we "load" three virtual pages (with fake data), each of them contains 50 items. Then we re-fill the same array at the next scroll-event.

lockee14 commented 5 years ago

I don't know if it can help but here is my solution: https://stackblitz.com/edit/angular-mat-table-infinite-scroll-with-sort?file=src%2Fapp%2Fapp.component.ts

No use of cdk virtual scroll just mat-table, data can also be sorted.

angular-automatic-lock-bot[bot] commented 5 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.