Creating a treeview that loads data on demand: A step-by-step guide

Is it possible to create a tree structure that loads data on demand without using external libraries? I have a backend with methods for fetching root level nodes and children of parent nodes. The goal is to build a tree where clicking on a node triggers the loading and drawing of new branches with their children, potentially at multiple levels deep. How can this be achieved using mat-tree in Angular? I attempted using a recursive function with *ngFor but encountered issues with mat-tree compatibility. Ideally, I'm looking for something similar to the functionality demonstrated in this example.

Answer №1

I have developed a service with two key functions:

getRootNodes(){}

and

getChildren(node:any){}

The getRootNodes function retrieves the first level of root nodes.

Regarding getChildren(nodes:any), it returns the children, but not just as an array of strings. Instead, it provides an array of objects with a property "isExpandable," which is essential for material-tree to determine if a child node has further children.

The next step involves employing our service in the DinamicDataSource. The toggleNode function must utilize the service. If !expands is the code previously placed under setTimeOut, there is no need for a setTimeOut anymore.

If expand=true, we invoke the service and subscribe to the data. The code that was originally under setTimeOut now resides within the subscription block.

In both cases, it is necessary to call this.dataChange.next(this.data).

toggleNode(node: DynamicFlatNode, expand: boolean) {
    const index = this.data.indexOf(node);
    if (!expand)
    {
      let count = 0;
        for (let i = index + 1; i < this.data.length
          && this.data[i].level > node.level; i++, count++) {}
        this.data.splice(index + 1, count);
        this.dataChange.next(this.data);
    }
    else
    {
    node.isLoading = true;
    this.dataService.getChildren(node.item).subscribe(children=>{
      if (!children || index < 0) { // If no children, or cannot find the node, no op
        node.isLoading = false;

        return;
      }
      .
      .
      .
    })
    }
  }

The final modification involves transferring the constructor's functions to ngOnInit in the TreeDynamicExample.

ngOnInit()
  {
    this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
    this.dataSource = new DynamicDataSource(this.treeControl, this.dataService);
    this.dataService.getRootNodes().subscribe(res=>{
      this.dataSource.data = res.map(name => new DynamicFlatNode(name, 0, true));
    })
  }

Prior to assigning this.dataSourceData to a DynamicFlatNode, obtaining the data and processing it within the subscribe block is crucial.

Update: Demystifying the DynamicDataSource.

. . .

I hope this explanation clarifies the functionality behind the dynamic tree. Here is the link to the stackblitz, where I added simple buttons to add a node, add a subnode, and change a node.

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

What sets apart the Partial and Optional operators in Typescript?

interface I1 { x: number; y: string; } interface I2 { x?: number; y?: string; } const tmp1: Partial<I1> = {}, tmp2: I2 = {}; Can you spot a clear distinction between these two entities, as demonstrated in the above code snippet? ...

Personalize your Client-Id for Paypal

Currently integrating PayPal's Smart Payment Buttons into my Angular project. The index.html file contains the following script: <script src="https://www.paypal.com/sdk/js?client-id=MY_CLIENT_ID"> </script> I am working on developi ...

Ensure that at least one of two props is mandatory in a functional component while using typescript

Consider a scenario where we have a functional component: // my-component.tsx interface Props { propA?: string; propB?: number; } const MyComponent = ({propA, propB}: Props) => { return <div>Hello world</div> } Now, let's incorp ...

Encountering an error message indicating module '@schematics/angular/utility/json-file' cannot be found while attempting to set up Angular universal

Encountering this issue while attempting to install Angular Universal by running the command add @nguniversal/express-engine --clientProject [project name]. My current Angular version is 7. I attempted to resolve it by executing npm install @schematics/&l ...

Whenever I try to import a function, I encounter the error message "no exported member."

I am facing an issue with my node/typescript application where I am attempting to import a function from another file. In order to export it, I utilized exports.coolFunc = coolFunc, and for importing, I used import {coolFunc} from '../controller/coolS ...

Issue encountered with Typescript and Request-Promise: Attempting to call a type that does not have a call signature available

I have a server endpoint where I want to handle the result of an asynchronous request or a promise rejection by using Promise.reject('error message'). However, when I include Promise.reject in the function instead of just returning the async requ ...

The browser is throwing errors because TypeScript is attempting to convert imports to requires during compilation

A dilemma I encountered: <script src="./Snake.js" type="text/javascript"></script> was added to my HTML file. I have a file named Snake.ts which I am compiling to JS using the below configuration: {target: "es6", module: "commonjs"} Howeve ...

Eliminating TypeScript errors in JavaScript files using Visual Studio Code

While working in JS files, I keep encountering TypeScript errors in VS Code. Is there a way to turn this off? I've already tried adding the following line to my settings without success: "typescript.validate.enable": false You can view the error her ...

Display various react components based on the value of the property

I am in the process of creating an input component in ReactJs with typescript. The input can vary in types such as text, date, select, or textarea. Depending on the type provided, the displayed control will differ. For example, if set to text, <input t ...

Insert a new item into the array located within an Observable entity

In my angular application, I have a page where I am showcasing an object that contains an array of comments within it. This object is loaded into my class as an Observable and then displayed in the HTML using: <div class="container-fluid mt--7" ...

Creating validation rules for a form that includes a From Date and a To Date

Looking to implement validation for the from date and to date fields within a template-driven form. Is there a way to ensure that the "from date" is always greater than the "to date," and vice versa? Additionally, I would like to find a way to reuse this ...

How can I access the component name and parameters during the NavigationEnd event?

We are currently setting up Google Analytics and we want to track the URL, parameters, and components in GA. this.router.events .pipe( filter(event => event instanceof NavigationEnd) ) .subscribe((event: NavigationEnd) => ...

Setting the value of a dropdown menu by updating a form

Currently, I am utilizing a select element with Angular: <select class="form-select form-select-md" formControlName="MaritalStatus"> <option value="0" selected>Select...</option> <option *ngFor=&qu ...

display ngx spinner 1 second later

Implementing a centralized interceptor that logs all HTTP requests and uses ngx-spinner for each request. The requirement is to delay the loader by 1 second after the HTTP request, showing the spinner only if the response is still in progress after the del ...

Angular 2 applications with routing capabilities running within nested iframes

Currently, I am in the process of developing an Outlook add-in using Angular 2. Since it is an outlook hosted app, it will be run within a cross-domain iframe and I have no control over this setup. The iframe is also sandboxed with specific properties incl ...

Using the same object name to extend an interface in TypeScript

export interface sample { library:{ opening:number; closing:string; } } interface shelves extends example{ library:{ closing:null } } Can you expand upon an object in typescript? Sometimes I only need to utilize the initial structure ...

Make sure to load Meteor.user() prior to initializing Angular 2

I am encountering an issue while setting up a new Meteor - Angular2 application where I am struggling to verify the logged-in user within my router. Below is my current auth-guard.service.ts content featuring an AdminAuthGuard that utilizes implements Can ...

Trouble with Angular not Displaying BootStrap 5.0 Styles

Trying to implement both BootStrap and Angular into the project, I successfully applied the styles by adding the following line in the index file: <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="sty ...

Encountered error: Unable to locate module - Path 'fs' not found in '/home/bassam/throwaway/chakra-ts/node_modules/dotenv/lib' within newly generated Chakra application

Started by creating the app using yarn create react-app chakra-ts --template @chakra-ui/typescript. Next, added dotenv with yarn add dotenv Inserted the following code block into App.tsx as per the instructions from dotenv documentation: import * as dote ...

Having trouble with NextJS TypeScript and the randomUUID?() function? If you're seeing the error TS2386 that says "Overload signatures must all be

In my project setup, I have a mono-repo structure utilizing Lerna for managing 2 NextJS projects and 1 shared project. I recently attempted to integrate typescript. The NextJS projects seem to be functioning correctly (following the documentation), but I ...