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

Is it possible to include a visible comment in an ajax call that can be viewed in Fiddler when analyzing the outgoing data?

Here is an example of the code I am working with: $.ajax({ cache: false, url: "/xx" }).done(onAjaxDone).fail(function (jqXHR, textStatus, errorThrown) { Dialog.Alerts.ajaxOnFailure(jqXHR, textStatus, err ...

In the strict mode tree, a reference named "grid" has been discovered

I encountered the following warning in the console: Warning: A string ref, "grid", has been found within a strict mode tree. String refs can potentially lead to bugs and should be avoided. It is recommended to use useRef() or createRef() instead. T ...

Tips for using a JavaScript variable in a PHP file on WordPress

As a newcomer to Wordpress, I am trying to navigate the Theme Editor. Within it, I found a javascript file that looks like this: const isMenuOpen = false; function toggleMenu() { alert("toggle"); isMobileMenuOpen = !isMobileMenuOpen; } ...

Is there a way to determine the model name programmatically within a Sails.js lifecycle callback?

Two models are present, with one model extending from the other. For all sub-models to inherit a lifecycle callback defined in BaseObject, I need a way to retrieve the name of the model being acted upon within the callback. This information is crucial for ...

Revolutionary Approach to Efficiently Handle Multiple rows with Jquery

Greetings to everyone, I am currently in the process of developing an application that retrieves data from a database via AJAX by calling a .php file. Within this app, I have a table with 4 columns. The first two columns consist of dropdown menus, the thi ...

Which is causing the block: the event loop or the CPU?

example: exports.products = (req, res) => { let el = 1; for (let i = 0; i < 100000000000000; i++) { el += i; } console.log(el); ... ... ... res.redirect('/'); }; If I include a loop like this in my code, which resour ...

eliminate element from array and refresh table

I am facing an issue with my code where I have an array bound to ng-repeat and a button. When the user clicks on the button, I want to remove an element from the array. Here is my current code snippet: var app=angular.module('app',[]); app.con ...

Include a new class in the classList of an element at a specific index

Is it possible to add a class to a specific position in order to maintain a certain order, especially when it goes against the logic that targets the class based on its position? link.closest('item').classList.add('c-class') // Contrad ...

Creating a nested/child route structure within the Angular 2 router

Looking to implement nested routing for mypage/param1/1/param2/2 format in the URL. The first parameter is represented by 1 and the second one by 2. It's imperative that there are always two parameters, otherwise an error should be displayed. However, ...

Unable to retrieve information from a function in Vue.js (using Ionic framework)

When attempting to extract a variable from a method, I encounter the following error message: Property 'commentLikeVisible' does not exist on type '{ toggleCommentLikeVisible: () => void; This is the code I am working with: <template& ...

I am looking to access a public method from a different component in Angular 2

Trying to access the headerExpand property from app.component is causing an error message in the console: metadata_resolver.js:559 Uncaught Error: Invalid providers for "Page1" - only instances of Provider and Type are allowed, got: [?undefined?] page1 ...

Dealing with onChange value in a date in reactjs is a common challenge that developers

I'm currently working on a basic date input component in React, but I've run into an issue when trying to change the value. Every time I update it, it always displays "1970-01-01". If anyone has any suggestions on how to fix this problem, I woul ...

Strange behavior: JS object values disappear when accessed statically

I'm feeling puzzled. The issue at hand is that an object seems to lose its values within a loop based on the method of access. When accessed through variables, everything appears to be in order. However, when using static expressions identical to the ...

Exploring Attack on Titan alongside the concept of dynamic route templates in coding

I am currently working on creating a factory for an UrlMatcher. export const dummyMatcher: UrlMatcher = matchUrlFn(sitemap as any, 'dummy'); export const routes: Routes = [ { matcher: dummyMatcher, component: DummyComponent }, { path: &apos ...

Adjust the height of an element using CSS based on the height of another

Is there a way to have two divs per row, where the second div always displays its full content and the height of the first div matches the height of the second div? If the content in the first div exceeds the height, it should be scrollable. I've atte ...

React - optimize performance by preventing unnecessary re-renders of an object property

In my current project, I am working with an auction object that has two properties: remainingTime and amount. To enhance user experience, I integrated a countdown timer using the react-countdown-now library to display the remainingTime. Additionally, there ...

React Higher Order Component (HOC) encountered an ESLint issue: spreading props is not

Does eslint lack intelligence? The Higher Order Component (HOC) is quite generic, so I struggle to specify the incoming options/props as they are dynamic based on the component being wrapped by this HOC at any given time. I am encountering an error statin ...

Are there any available resources for comparing the performance of JavaScript libraries?

In preparing a presentation for my company, I am outlining the reasons for choosing jQuery as our primary JavaScript / AJAX library. While most of the work is already completed, it would be beneficial to include a comparison with other libraries, particul ...

The Angular material datepicker is not accurately capturing the date I am trying to select

I am facing an issue with the Angular Material datepicker where it does not select the date I choose. Instead, in my AngularJS controller, I always get the sysdate even if I select another date. Can anyone help me figure out what I am doing wrong? Here is ...

Unveiling the mysteries of JSONP in conjunction with AJAX

JSONP allows for bypassing the same origin policy in JavaScript by using <script> tags to load third party data. However, I am uncertain about how JSONP is utilized together with AJAX. My assumption is that: When an AJAX call is initiated, a <sc ...