Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my angular app becoming very slow after changing the data backing a mat-tree?

I am implementing the angular/material tree component and having some problems. After saving changes to the tree I am resetting the data backing the tree (which works) however the app then becomes incredibly slow, expanding nodes can take about 8 seconds.

What makes this even weirder is that the code that actually manipulates the data source is run in other places, such as adding a new child to the tree - we want the UI to update, and this does not cause a problem. It is only when saving that the app becomes slow.

save(): void {
    const trees = this.flattenedTree.filter(node => this.isRootNode(node));

    this.serviceThatHasNoSideEffects.save(trees)
        .then(result => {
            this.tree = result;
            this.flattenedTree = this.getFlattenedTree();
            this.refreshTree();
        });
}

private refreshTree() {
    const data: any[] = this.flattenedTree
        .filter(x => this.isRootNode(x))
        .filter(x => x.children.length > 0 || x.id === this.focusId);

    this.nestedDataSource.data = null;
    this.nestedDataSource.data = data;

    const focusNode = this.getNode(this.focusId);
    this.nestedTreeControl.expand(focusNode);
}

private addChild(parentNode: any, childNode: any) {
    if (!this.getNode(parentNode)) {
        this.flattenedTree.push(parentNode);
    }

    if (!this.getNode(childNode)) {
        this.flattenedTree.push(childNode);
    }

    parentNode.children.push(childNode);

    this.refreshTree();
    this.nestedTreeControl.expand(parentNode);
}

EDIT:

changing refresh tree to create a completely new data source solves the slow issue (memory leak?) but not adding a child isnt displaying in the UI. Although the child is there on the flattened tree so should be displayed.

private refreshTree() {
    const data: any[] = this.flattenedTree
        .filter(x => this.isRootNode(x))
        .filter(x => x.children.length > 0 || x.id === this.focusId);

        this.nestedDataSource = new MatTreeNestedDataSource<theTreeType>();
    this.nestedDataSource.data = data;

    const focusNode = this.getNode(this.focusId);
    this.nestedTreeControl.expand(focusNode);
}

EDIT: here is the html backing it. pretty standard.

       <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
            <li class="mat-tree-node">
                <button mat-icon-button disabled></button>
                {{node.uniqueName}}
            </li>
        </mat-tree-node>

        <!--when has nested child-->
        <mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
            <li>
                <div class="mat-tree-node">
                    <button mat-icon-button matTreeNodeToggle>
                        <mat-icon>
                            {{nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
                        </mat-icon>
                    </button>
                    {{node.uniqueName}}
                </div>
                <ul [class.invisible]="!nestedTreeControl.isExpanded(node)">
                    <ng-container matTreeNodeOutlet></ng-container>
                </ul>
            </li>
        </mat-nested-tree-node>
    </mat-tree>
like image 921
Craig Avatar asked Jun 29 '18 11:06

Craig


People also ask

Why is my angular app so slow?

Your app is rendering too often. Let's start with this quite common issue: your application re-renders components unnecessarily, making your application slower than it could be. This is both easy to solve and easy to cause.

Is angular material slow?

Many Angular developers are frustrated with Angular because they say it is slow. Some think that it's hard to build a fast Angular application. Especially given that the bundle sizes of its biggest rivals - React & Vue. js - are usually about half as small and take about half the time to parse and run the JavaScript.

What is Mat tree in angular?

The <mat-tree> directive is used to create trees in Angular. The tree is a type of structure that contains data organized in a hierarchical way. Each data item is represented by a node of the tree. The Angular Material Tree is an enhancement over the previous structure, Component Dev Kit Tree (cdk-tree).


2 Answers

Although the accepted answer seems to offer some speed improvement, the solution that finally did it for me (in Angular 8) is this:

https://stackoverflow.com/a/59655114/134120

Change the line from the official examples:

<ul [class.example-tree-invisible]="!treeControl.isExpanded(node)">

to this:

<ul *ngIf="treeControl.isExpanded(node)">

so that collapsed subtrees are not loaded in the DOM at all.

like image 196
AsGoodAsItGets Avatar answered Sep 20 '22 15:09

AsGoodAsItGets


it took me a few hours to get it working but here is the change I made:

// cdk tree that mat tree is based on has a bug causing children to not be rendered in the UI without first setting the data to null
this.nestedDataSource.data = null;
// mat-tree has some sort of memory leak issue when not instantiating a new MatTreeNestedDataSource which causes the app to become very slow
this.nestedDataSource = new MatTreeNestedDataSource<LocationHierarchyNodeDataModel>();
this.nestedDataSource.data = data;

The displaying children issue I found here: https://github.com/angular/material2/issues/11381

like image 25
Craig Avatar answered Sep 18 '22 15:09

Craig