Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular material CDK tree component with virtual scroll

Angular Material CDK tree component documentation says:

"Flat trees are generally easier to style and inspect. They are also more friendly to scrolling variations, such as infinite or virtual scrolling"

Any ideas how to apply virtual scrolling to CDK flat tree?

I have a massive tree to render and right now it is so slow and when I open all nodes recursively it will crash

I tried < cdk-virtual-scroll-viewport > @angular/cdk-experimental but did not figure it out how to integrate it with tree component

like image 892
Ragnar Avatar asked Oct 02 '18 10:10

Ragnar


People also ask

What is Virtual Scrolling in Angular 7 Material CDK?

Virtual Scrolling is different from infinite scroll - where it renders batches of elements and then when user goes to bottom of the list, it renders the rest. In this tutorial, we create many simple examples that show you how to work with Angular 7 Material CDK – Virtual Scrolling.

Does the cdktable Component support virtual scroll?

The CdkTable (or MatTable) component does not support virtual scroll YET. The virtual scroll support baked into @angular/cdk is still in it's experimental phase - this will change in version 7. However, when this feature lands the next step will be to implement it for the table. I will explain why.

How to install Material CDK in Angular 2?

If you are following along: In the stackblitz demo click on dependencies, it is just beneath window where project file are listed see screen shot below, type @angular/cdk and hit enter this will install material cdk. If you want to install it inside your angular cli project simply type npm i --save @angular/cdk

What is the difference between *ngfor and *cdkvirtualfor?

*cdkVirtualFor is similar to *ngFor directive to which we provide the data to be displayed. *cdkVirtualFor accepts data in the form of an Array, Observable<Array>, or a custom DataSource. The DataSource for the virtual scroll is similar to the one used in the pagination example and used in other table and tree material components.


2 Answers

I know this is old, but I came across this thread while trying to figure out the same exact thing, and after much experimentation, I've figured out a basic working example of a virtually scrolling flat tree that requires VERY LITTLE MODIFICATION if you already have a working cdk-tree

The key to my solution was to abandon the cdk-tree directives and use my MatTreeFlatDataSource and FlatTreeControl directly with *cdkVirtualFor. You probably already have these objects set up to pass as inputs into cdk-tree. cdk-tree is actually just a very light wrapper around these two objects that are doing all of the heavy lifting.

Here's a stackblitz, for a more concrete example: https://stackblitz.com/edit/angular-b5nkkd?file=src/app/app.component.html

Here's what it contains:

  • Two scrolling flat trees that draw from the same underlying data source and are controlled by the same underlying tree control (i.e, they hold the same data and whatever you do to one tree will be reflected in the other tree as well)

  • The first tree uses cdk-tree directives, but I couldn't figure out how to get it to work with CDK virtual scroll so it renders all the nodes

  • The second tree does NOT use cdk-tree, but I was able to get virtual scrolling to work cleanly with very little changes. As a result, you have to do styling and some basic logic yourself, but if you look at the difference in template code in the stackblitz, you'll see that it's not so bad.

  • I'm displaying the number of nodes each scroll container is rendering to demonstrate that virtual scrolling is working in one and not the other

like image 182
Ariel Avatar answered Sep 23 '22 20:09

Ariel


The main function of the virtual viewport is to keep track of scroll events and notify you which elements are currently on screen. Using this information, you can modify the datasource of the tree to only be the nodes that are on screen.

The problem is that right now, the viewport really only works well with items of a consistent height. When you expand a node of the tree, that node has a height that is inconsistent with the rest of the closed ones. To get around this, you may be able to add the child nodes to the virtual viewport's datasource whenever a node is expanded.

For now, I will ignore the expanded node problem.

To get basic virtual scrolling with the tree, add this to your template:

<cdk-virtual-scroll-viewport itemSize="48" style="height: 200px;">
  <ng-container *cdkVirtualFor="let item of fullDatasource"></ng-container>

  <mat-tree [dataSource]="dataSource" [treeControl]="treeControl">...</mat-tree-node>
  </mat-tree>
</cdk-virtual-scroll-viewport>

We create the viewport, telling it the size of each node. We then add the virtualForOf, passing in the fullDatasource so that the viewport knows how tall it needs to be. This might be cheating a bit because I believe the intended use of virtualForOf is that the template includes the items to be scrolled, but keeping it empty seems to work.

The only thing left is to make sure the tree's datasource is only the visible items of the full datasource. We'll change how we declare it initially in the constructor, but this is the more exciting part:

  ngAfterViewInit() {
    this.virtualScroll.renderedRangeStream.subscribe(range => {
      console.log(range, 'range')
      this.dataSource.data = this.fullDatasource.slice(range.start, range.end)
    })
  }

We subscribe to the renderedRangeStream which emits a range whenever the scroll changes. Whenever that happens, we simply set the datasource equal to the appropriate slice!

Stackblitz with result Hopefully this is enough to get you started!

like image 30
Benjamin Kindle Avatar answered Sep 19 '22 20:09

Benjamin Kindle