Having trouble displaying child nodes in MatTreeView with Angular 14?

In an Angular project, I am attempting to display a private group's data from GitLab (utilizing a public one for testing purposes). To achieve this, I have implemented the NestedTreeView component. While the parent nodes are displaying correctly, I am encountering difficulties in rendering their children. The structure of the fetched data from GitLab's API aligns with what the TreeView component expects. Here is the relevant code snippet:

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" class="example-tree">
  <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
      {{node.name}}
  </mat-tree-node>
  <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
      <div class="mat-tree-node">
        <button mat-icon-button matTreeNodeToggle
                [attr.aria-label]="'Toggle ' + node.name">
          <mat-icon class="mat-icon-rtl-mirror">
            {{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>

Screenshot of the data in the console

Visual representation of how it appears in the template

Answer №1

One of the primary reasons why these elements are hidden is due to the asynchronous nature of the getNodes(..).subscribe function call. To display them, you will need a mechanism to wait for all the elements to be fetched. One potential solution could be to utilize the forkJoin operator.

  fetchRoots() {
    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;
        },
      });
    })
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Closing the video on an HTML5 player using an iPad

My task is to incorporate a video into a website with a button to close and stop the video. Once closed, an image will appear below. Everything works perfectly on all browsers. The issue arises on the iPad... On the iPad, the "close" button does not wor ...

Executing asynchronous operations and handling responses in Node.js with Express

While I am still getting the hang of asynchronous functions and callbacks in Node.js, my current struggle lies in figuring out how to return a response after reading data from a file during an asynchronous operation. I have managed to send a response usin ...

Ways to implement the flow of change occurrences in the mat-select component

Seeking assistance with utilizing the optionSelectionChanges observable property within Angular Material's mat-select component. This property provides a combined stream of all child options' change events. I'm looking to retrieve the previ ...

Exploring the World of Html

I'm struggling with an HTML problem related to a web programming class I'm taking. The assignment involves creating a video game using HTML and JavaScript, where an image moves randomly on the screen and the player must click on it as many times ...

Utilizing Typescript version 1.5 alongside window.event.ctrlKey

When I need to debug, I occasionally check if the ctrl key is pressed for certain secret actions. This check may be included in any function, not necessarily an event handler itself (it could be a callback or an event handler). In my TypeScript code, I us ...

Is it possible to extract information from a form's POST request without relying on the traditional "action" attribute within form elements?

Last night, I was experimenting with ExpressJS and discovered something interesting when working with a simple code snippet: app.post('/contact', function(req, res, next) { res.send('Congratulations! You have submitted the form'); }) ...

Encountering a situation where d3.events is returning null within Angular 2 TypeScript code

Seeking to enhance my d3 maps with tooltips, I came across a helpful code snippet at this link However, upon implementing the same code in an Angular 2 TypeScript file, an error emerged: Error: Cannot read property 'transition' of undefined Th ...

Having trouble with nodeJS when running the command "npm install"?

Can anyone help me understand why I'm encountering issues when running "npm install"? Whenever I run npm install, I am bombarded with numerous errors. npm ERR! Windows_NT 10.0.10586 npm ERR! argv "C:\\Program Files\\nodejs&bsol ...

Implementing a restriction clause while executing a load additional data feature

I'm currently working on implementing a basic load more function for my web page. Right now, the page displays 8 results from the database. When the user scrolls, a load more button appears. Clicking this button triggers an ajax request to another PH ...

React Timer App: The setInterval function is being reset after each render operation

I'm currently working on a straightforward timer application that will begin counting seconds when a button is clicked. To implement this, I am utilizing react hooks. import React, { useState } from 'react' function Timer() { const [sec ...

Set up webpack on your Mac using npm

Seeking help to install webpack using npm: sudo npm install -g webpack The following error message is encountered: node-pre-gyp WARN Using needle for node-pre-gyp https download node-pre-gyp WARN Pre-built binaries not installable for <a href="/cdn- ...

Creating a custom AngularJS HTTP interceptor that targets specific URLs

Is there a way to configure an $http interceptor to only respond to specific URL patterns? For example, I want the interceptor to only intercept requests that match "/api/*" and ignore any other requests. ...

Troubleshooting Issue with Nested ng-include in AngularJS: Difficulty arises when the parent element with the ng-include attribute is dynamically added using the ng-

Click here to see a demo plunker that will help you understand my issue. On my main page, I have a table. Each table row is followed by a hidden empty row. When the first row is clicked, I use a directive to inject HTML into the empty row below it. Main ...

Modifying the class of multiple images within an array

I am excited to share my first post here and express my gratitude for all the solutions I have found on this platform. I encountered an issue with using .removeClass and .addClass in my recent program. I am loading multiple pictures into an array called F ...

Ensuring TypeORM constraint validations work seamlessly with MySQL and MariaDB

I recently started using TypeORM and I'm trying to incorporate the check decorator in my MySQL/MariaDB database. However, after doing some research on the documentation and online, it seems that the check decorator is not supported for MySQL. I'v ...

Divide JSON information into distinct pieces utilizing JQuery

$.ajax({ type: 'POST', url: 'url', data: val, async: false, dataType: 'json', success: function (max) { console.log(max.origin); } ...

Managing business logic in an observable callback in Angular with TypeScript - what's the best approach?

Attempting to fetch data and perform a task upon success using an Angular HttpClient call has led me to the following scenario: return this.http.post('api/my-route', model).subscribe( data => ( this.data = data; ...

Error: Uncaught TypeError when using a for loop in Vue and GraphQL

I encountered a TypeError while attempting to iterate through a GraphQL query in my Vue project. The script snippet in question is as follows: <script> import { useQuery } from "@vue/apollo-composable"; import gql from "graphql-tag&qu ...

Having trouble adding @angular/fire to my Angular project

Having trouble adding Firebase authentication to my Angular project, specifically when running npm install @angular/fire. I keep encountering the following error: > npm ERR! code ERESOLVE > npm ERR! ERESOLVE unable to resolve dependency tree > ...

Using ngFor in Angular 6 to create a table with rowspan functionality

Check out this functional code snippet Desire for the table layout: <table class="table table-bordered "> <thead> <tr id="first"> <th id="table-header"> <font color="white">No.</font> </th> <th id="table-hea ...