Menu Close

Angular Material — Nested Tree

Angular Material is a popular UI framework based on Material Design for Angular.

In this article, we’ll look at how to use Angular Material into our Angular project.

Nested Tree

We can add a tree with nesting withn the mat-nested-tree-node component.

For example, we can write:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTreeModule } from '@angular/material/tree';
import { MatButtonModule } from '@angular/material/button';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MatTreeModule,
    MatButtonModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { NestedTreeControl } from '@angular/cdk/tree';
import { Component } from '@angular/core';
import { MatTreeNestedDataSource } from '@angular/material/tree';

interface FoodNode {
  name: string;
  children?: FoodNode[];
}

const TREE_DATA: FoodNode[] = [
  {
    name: 'Fruit',
    children: [
      { name: 'Apple' },
      { name: 'Banana' },
      { name: 'Fruit loops' },
    ]
  }, {
    name: 'Vegetables',
    children: [
      {
        name: 'Green',
        children: [
          { name: 'Broccoli' },
          { name: 'Brussels sprouts' },
        ]
      }, {
        name: 'Orange',
        children: [
          { name: 'Pumpkins' },
          { name: 'Carrots' },
        ]
      },
    ]
  },
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  treeControl = new NestedTreeControl<FoodNode>(node => node.children);
  dataSource = new MatTreeNestedDataSource<FoodNode>();

  constructor() {
    this.dataSource.data = TREE_DATA;
  }

  hasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0;
}

app.component.html

<div>
  <mat-tree [dataSource]="dataSource" [treeControl]="treeControl"
    class="example-tree">
    <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
      <li class="mat-tree-node">
        <button mat-icon-button disabled></button>
        {{node.name}}
      </li>
    </mat-tree-node>
    <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
      <li>
        <div class="mat-tree-node">
          <button mat-icon-button matTreeNodeToggle>
            <mat-icon class="mat-icon-rtl-mirror">
              {{treeControl.isExpanded(node) ? '&#8595; ' : '&#8594;'}}
            </mat-icon>
          </button>
          {{node.name}}
        </div>
        <ul [class.example-tree-invisible]="!treeControl.isExpanded(node)">
          <ng-container matTreeNodeOutlet></ng-container>
        </ul>
      </li>
    </mat-nested-tree-node>
  </mat-tree>
</div>

styles.css

.example-tree-invisible {
  display: none;
}

.example-tree ul,
.example-tree li {
  margin-top: 0;
  margin-bottom: 0;
  list-style-type: none;
}

We add the MatTreeModule to let us add the tree nodes.

The MatButtonModule lets us add the buttons for toggling the child nodes.

In app.component.ts , we have a nested array with the nested data.

Then we pass that into the MatTreeNestedDataSource constructor to create the data.

We also have to create the NestedTreecontrol instance and bind that to the mat-tree .

The hasChild method is also needed to determine if a node has child nodes.

In the app.component.html file, we show the mat-tree with the mat-tree-node to show flat tree nodes.

And the mat-nested-tree-node shows the nested tree node.

the *matTreeNodeDef are different for each.

The treeControl.isExpanded method lets us check whether the node is expanded and show content accordingly.

Conclusion

We can add a nested tree with Angular Material.

Posted in Angular, Angular material