Home > Back-end >  MatTreeView not showing children - Angular 14
MatTreeView not showing children - Angular 14

Time:07-27

I'm trying to show a private group data from gitlab ( using a public one for testing ) and i'm using the Angular NestedTreeView to show each group with their subgroup, the parent nodes are showing normaly but i can't find a way to show their children, i have mapped the data to the way that the TreeView wants, the array with the data that i fetched from gitlab's api is showing fine with the parents and their children. Here's the code:

data.ts

export interface Data {
    name: string;
    id?: string;
    children?: Data[]
}

data.service.ts

@Injectable({
  providedIn: 'root'
})
export class DataService {

  constructor(public http: HttpClient) { }

  getEndpoint(id: string): string
  {
    return `https://gitlab.com/api/v4/groups/${id}/subgroups`
  }
   getRoot(): Observable<Data[]>{
    
    return this.http.get<Data[]>(this.getEndpoint("9970")).pipe(
      map((res: any) =>
        res.map((data: Data) =>
        {
          return {
            name: data.name,
            id: data.id,
           
          }
        })
      )
    )
    }

  getNodes(subid: string): Observable<Data[]>
  {
    return this.http.get<Data[]>(this.getEndpoint(subid)).pipe(
      map((res: any) =>
        res.map((data: Data) =>
        {
          return {
            name: data.name,
            id: data.id,
          }
        })
      )
    )
  } 
  
  
}

sidebar.component.ts

@Injectable({
   providedIn: 'root' })
@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.scss']
})
export class AppSidebarComponent implements OnDestroy,OnInit {
  mobileQuery: MediaQueryList;
  private _mobileQueryListener: () => void;


  result: Data[] = [];
  treeControl = new NestedTreeControl<Data>(node => node.children);
  dataSource = new MatTreeNestedDataSource<Data>();

  constructor(
    changeDetectorRef: ChangeDetectorRef,
    media: MediaMatcher,
    public menuItems: MenuItems,
    public http: HttpClient,
    public dataService: DataService
  ) {
    this.mobileQuery = media.matchMedia('(min-width: 768px)');
    this._mobileQueryListener = () => changeDetectorRef.detectChanges();
    this.mobileQuery.addListener(this._mobileQueryListener);


    this.getRoots();
  }


  ngOnInit(): void {
  }

  getRoots()
  {
    this.dataService.getRoot().subscribe(response => {
      this.result =  response
      this.result.forEach(directory => {
        let nodeList: Data[]= []
        this.dataService.getNodes(directory.id!).subscribe(response => {
          nodeList = <Data[]> response
          if(nodeList.length>0)
            directory.children = nodeList;
          nodeList = [];
        })    
      });
      console.log(this.result);
      this.dataSource.data = this.result;
    })
  }
  ngOnDestroy(): void {
    this.mobileQuery.removeListener(this._mobileQueryListener);
  }
  hasChild = (_: number, node: Data) => !!node.children && node.children.length>0;

}

sidebar.component.html

<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" >
  <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
      {{node.name}}
  </mat-tree-node>
  <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
      <div >
        <button mat-icon-button matTreeNodeToggle
                [attr.aria-label]="'Toggle '   node.name">
          <mat-icon >
            {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
          </mat-icon>
        </button>
        {{node.name}}
      </div>
      <div [class.example-tree-invisible]="!treeControl.isExpanded(node)"
          role="group">
        <ng-container matTreeNodeOutlet></ng-container>
    </div>
  </mat-nested-tree-node>
</mat-tree>

The data in the console

How it shows in the template

CodePudding user response:

The main reason why they are not shown is that calling getNodes(..).subscribe is not sync so u'll need a way to wait for them all. forkJoin is possible solution

  getRoots() {
    this.dataService.getRoot().subscribe((response) => {
      const result$ = forkJoin(
        response.map((directory) => {
          return this.dataService.getNodes(directory.id!).pipe(
            map((children) => {
              return {
                ...directory,
                children,
              };
            })
          );
        })
      );
      result$.subscribe({
        next: (result) => {
          this.result = result as Data[];
          this.dataSource.data = this.result;
        },
      });
    })
  }
  • Related