0
votes

I am new to the Angular framework and want to generate a mat-tree from REST API which is made in MongoDB. I have created a model in the backend for retrieving data from the backend database. Below is a code which is written on the backend server configuration.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

let MainTree = new Schema({
   id: {
      type: String
   },
   name: {
      type: String
   },
   children: {
      type: Array
   }
}, {   
      collection: 'TreeData'
})

module.exports = mongoose.model('MainTree', MainTree)

tree.routee.js this file defining route and functions which can be called by service api.

const express = require('express');
const app = express();
const treeRoute = express.Router();

let TreeData = require('../models/MainTree');

treeRoute.route('/').get((req, res) => {
    TreeData.find((error, data) => {
      if (error) {
        return next(error)
      } else {
        res.json(data)
      }
    })
})
module.exports = treeRoute;

tree.service.ts this is service api

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})

export class TreeService {
  baseUri:string = 'http://localhost:4000/api';

  constructor(private http: HttpClient) { }
  getTreeData(){
    return this.http.get(`${this.baseUri}`);
 }
}

demo-tree.component.ts this is component.ts file which is getting data from backend via tree.service.ts

import { Component, OnInit } from '@angular/core';
import { TreeService } from '../service/tree.service';

@Component({
  selector: 'app-demo-tree',
  templateUrl: './demo-tree.component.html',
  styleUrls: ['./demo-tree.component.css']
})
export class DemoTreeComponent implements OnInit {
  Tree:any = [];
  constructor(private Data: TreeService) { }
  getData(){
    this.Data.getTreeData().subscribe((data) => {
      this.Tree = data;
     })    
  }
  ngOnInit() {
  }
}

demo-tree.component.html this is HTML file which is retrieving Tree Array, showing message 'There is no item added yet!' and this is right because we have not added any item or node in backend database.

<p *ngIf="Tree.length <= 0" class="no-data text-center">There is no item added yet!</p>

else showing mat-tree data like that.

I want to know how I can make a tree-like structure in my backend server and retrieve that data. Is there a way to generate a mat-tree from a Database? I have read the answer to this question but didn't appropriate for my requirement.

Thanks.

1
Can you show the service ? The service (and the api call) is working ? - TintinSansYeux
Yes, service api call is working and showing an empty array. - Malik Saqib Awan
An empty array ? Can you show the object you receive from api ? - TintinSansYeux
Okay, I am updating my question. Please see the service api call and backend function which is sending response as json object. - Malik Saqib Awan
@Angular now I have updated my question, can you now understand my problem? - Malik Saqib Awan

1 Answers

1
votes

Component.ts

/** File node data with nested structure. */
export interface FileNode {
  id: string;
  name: string;
  children?: FileNode[];
}

/** Flat node with expandable and level information */
export interface TreeNode {
  id: string;
  name: string;
  level: number;
  expandable: boolean;
}

/** The TreeControl controls the expand/collapse state of tree nodes.  */
treeControl: FlatTreeControl<TreeNode>;

/** The TreeFlattener is used to generate the flat list of items from hierarchical data. */
treeFlattener: MatTreeFlattener<FileNode, TreeNode>;

/** The MatTreeFlatDataSource connects the control and flattener to provide data. */
dataSource: MatTreeFlatDataSource<FileNode, TreeNode>;

ngOnInit() {
  this.getData();
  this.treeFlattener = new MatTreeFlattener(
    this.transformer,
    this.getLevel,
    this.isExpandable,
    this.getChildren,
  );

  this.treeControl = new FlatTreeControl<TreeNode>(this.getLevel, this.isExpandable);
  this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
}

getData(){
  this.Data.getTreeData().subscribe((data) => {
    this.Tree = data;
    this.dataSource.data = data;
  })    
}

/** Transform the data to something the tree can read. */
transformer(node: FileNode, level: number) {
  return {
    id: node.id,
    type: node.type,
    level: level,
    expandable: !!node.children
  };
}

/** Get the level of the node */
getLevel(node: TreeNode) {
  return node.level;
}

/** Return whether the node is expanded or not. */
isExpandable(node: TreeNode) {
  return node.expandable;
};

/** Get the children for the node. */
getChildren(node: FileNode) {
  return of(node.children);
}

/** Get whether the node has children or not. */
hasChild(index: number, node: TreeNode){
  return node.expandable;
}

Component.html

<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
  <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle matTreeNodePadding>
    <button mat-icon-button disabled></button>
    {{node.name}}
  </mat-tree-node>

  <mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
    <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}}
  </mat-tree-node>
</mat-tree>