[Fixed] DevExtreme TreeView not bind data from web api

Issue

I use DevExtreme TreeView to load the menus, one in the left side (for top menu), and one in the right side (for sub menu). The left one can bind data from web api normally, but the right one can not. I don’t know why. Here’s my code.

  1. .Net Core Web API
namespace MHIBS.WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class MenuController : ControllerBase
    {
        IRepository _repository;

        public MenuController(IRepository repository)
        {
            _repository = repository;
        }
        
        [HttpGet]
        public async Task<ActionResult<List<MenuModel>>> GetTopMenu()
        {
            var result = await Task.FromResult(_repository.GetAll<MenuModel>($"Select MenuId, MenuName, CaptionEN, Route, ParentId from [t_Menu] where ParentId is null order by MenuOrder", null, commandType: CommandType.Text));
            return result;
        }

        [HttpGet("{parentId}")]
        public async Task<ActionResult<List<MenuModel>>> GetSubMenu(Guid parentId)
        {
            DynamicParameters param = new DynamicParameters();
            param.Add("ParentId", parentId, DbType.Guid);
            var result = await Task.FromResult(_repository.GetAll<MenuModel>($"usp_GetSubMenu", param));
            return result;
        }
    }
}
  1. Angular service
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Guid } from 'guid-typescript';

@Injectable({
  providedIn: 'root'
})
export class AppService {
  private headers: HttpHeaders;
  baseURL: string = "http://localhost:44666/api/";

  constructor(private http: HttpClient) {
    this.headers = new HttpHeaders(
      {
        'Access-Control-Allow-Origin': '*'
      });
  }

  loadTopMenu() {
    return this.http.get(this.baseURL + "Menu");
  }

  loadSubMenu(parentId: Guid) {
    return this.http.get(this.baseURL + "Menu/" + parentId);
  }
}
  1. Angular component
<div id="page">
  <dx-responsive-box singleColumnScreen="sm" [screenByWidth]="screen">
    <dxi-row [ratio]="1"></dxi-row>
    <dxi-row [ratio]="2" screen="xs"></dxi-row>
    <dxi-row [ratio]="2"></dxi-row>
    <dxi-row [ratio]="1"></dxi-row>

    <dxi-col [ratio]="1"></dxi-col>
    <dxi-col [ratio]="2" screen="lg"></dxi-col>
    <dxi-col [ratio]="1"></dxi-col>
    <dxi-item>
      <dxi-location [row]="0" [col]="0" [colspan]="3" screen="lg"></dxi-location>
      <dxi-location [row]="0" [col]="0" [colspan]="2" screen="sm"></dxi-location>
      <div *dxTemplate class="header item">
        <p>Header</p>
      </div>
    </dxi-item>
    <dxi-item>
      <dxi-location [row]="1" [col]="1" [colspan]="3" screen="lg"></dxi-location>
      <dxi-location [row]="1" [col]="0" [colspan]="3" screen="sm"></dxi-location>
      <div *dxTemplate class="content item">
        <dx-tree-view id="sub-menu-treeview" [items]="subMenus" dataStructure="plain" parentIdExpr="parentId"
          keyExpr="menuId" displayExpr="captionEN" [width]="300" (onItemClick)="selectSubItem($event)"></dx-tree-view>
      </div>
    </dxi-item>
    <dxi-item>
      <dxi-location [row]="1" [col]="0" screen="lg"></dxi-location>
      <dxi-location [row]="2" [col]="0" screen="sm"></dxi-location>
      <div *dxTemplate class="left-side-bar item">
        <dx-tree-view id="top-menu-treeview" [items]="topMenus" dataStructure="plain" parentIdExpr="parentId"
          keyExpr="menuId" displayExpr="captionEN" [width]="300" (onItemClick)="selectTopItem($event)"></dx-tree-view>
      </div>
    </dxi-item>
    <dxi-item>
      <dxi-location [row]="2" [col]="0" [colspan]="3" screen="lg"></dxi-location>
      <dxi-location [row]="3" [col]="0" [colspan]="2" screen="sm"></dxi-location>
      <div *dxTemplate class="footer item">
        <p>Footer</p>
      </div>
    </dxi-item>
  </dx-responsive-box>
</div>
import { Component, ViewChild } from '@angular/core';
import { Guid } from 'guid-typescript';

import { AppService } from './app.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'mhibs-core';
  topMenus: Array<any>;
  subMenus: Array<any>;
  currentMenu: Menu;

  constructor(private service: AppService) {
  }

  ngOnInit() {
    this.service.loadTopMenu().subscribe((data: any) => this.topMenus = data);
  }

  screen(width) {
    return (width < 700) ? 'sm' : 'lg';
  }

  selectTopItem(e) {
    this.currentMenu = e.itemData;
    this.service.loadSubMenu(e.itemData.menuId)
      .subscribe({
        next(response) {
          this.subMenus = response;
          console.log(response);
        },
        error(err) { console.error('Error: ' + err); },
        complete() { console.log('Completed'); }
      }
      )
  }

  selectSubItem(e) {
  }
}

export class Menu {
  menuId: Guid;
  menuName: string;
  captionEN: string;
  route: string;
  parentId?: Guid;
}

when I click a treeview node on the left menu, I can get data from server as expected, but it can not bind to the right treeview. Please show me where I’m wrong. Thanks.

enter image description here

Solution

Here’s the answer for anyone needs it: https://supportcenter.devexpress.com/ticket/details/t987210/devextreme-treeview-not-bind-data-from-web-api/

Leave a Reply

(*) Required, Your email will not be published