Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 角度材质树不显示填充阵列的子元素_Angular_Tree_Angular Material 6 - Fatal编程技术网

Angular 角度材质树不显示填充阵列的子元素

Angular 角度材质树不显示填充阵列的子元素,angular,tree,angular-material-6,Angular,Tree,Angular Material 6,我试图在用户展开节点时动态加载子节点 问题是当我填充子数组时,mat tree没有显示子数组。如果我使用simple*ngFor显示相同的数据,当子数组添加了元素时,它会显示它们 我这里有一个工作示例: 这是代码和html ts 从'@angular/cdk/tree'导入{NestedTreeControl}; 从'@angular/core'导入{Component}; 从“@angular/material/tree”导入{MatTreeNestedDataSource}; 导出类Prop

我试图在用户展开节点时动态加载子节点

问题是当我填充子数组时,mat tree没有显示子数组。如果我使用simple*ngFor显示相同的数据,当子数组添加了元素时,它会显示它们

我这里有一个工作示例: 这是代码和html

ts

从'@angular/cdk/tree'导入{NestedTreeControl};
从'@angular/core'导入{Component};
从“@angular/material/tree”导入{MatTreeNestedDataSource};
导出类PropertyLevel{
建造师(
公共代码:string,
公共级别:布尔,
公共子属性:PropertyLevel[]
){}
}
@组成部分({
选择器:“我的应用程序”,
templateUrl:“./app.component.html”,
样式URL:['./app.component.css']
})
导出类AppComponent{
名称='角度';
nestedTreeControl:nestedTreeControl;
嵌套数据源:MatTreeNestedDataSource;
构造函数(){
this.nestedTreeControl=新的nestedTreeControl(this.\u getChildren);
this.nestedDataSource=new MatTreeNestedDataSource();
this.nestedDataSource.data=[
新的PropertyLevel('123',false,[]),
新PropertyLevel('345',true[
新的PropertyLevel('345.a',false,null),
新的PropertyLevel('345.b',true,[]),
]),
新的PropertyLevel('567',false,[]),
]; 
} 
hasNestedChild=(uz:number,nodeData:PropertyLevel)=>nodeData.subproperties;
private _getChildren=(节点:PropertyLevel)=>node.subproperties;
expandToggle(节点:PropertyLevel,isExpanded:boolean):void{
if(node.subperties&&node.subperties.length==0){
如果(node.code==“123”){
node.subproperties.push(新的PropertyLevel('123.a',false,null))
} 
else if(node.code==“567”){
node.subproperties.push(新的PropertyLevel('567.a',false,null));
node.subproperties.push(newpropertyLevel('567.b',false,null));
node.subproperties.push(新的PropertyLevel('567.c',false,null));
} 
}
}
}
html


  • {{node.code}
  • {{nestedTreeControl.isExpanded(节点)-'expand_more':'chevron_right'} {{node.code}
    • {{node.code}}
        {{subnode.code}
    这个故事的寓意(如果我错了,请纠正我)是,在Angularjs和Angularjs中,或者至少在材质树中,开发人员必须提供更改事件,而不是自动连接所有内容的更改检测,这减少了大量幕后对象的创建,使Angular更快、更精简

    因此,解决方案不是为子对象使用数组,而是使用BehaviorSubject,并向类添加一个方法以添加子对象

    我回到了嵌套节点树()示例(),调整了FileNode类并添加了addChild和addChildren方法

    export class FileNode {
      kids: FileNode[] = [];
      children:BehaviorSubject<FileNode[]> = new BehaviorSubject<FileNode[]>(this.kids);
      filename: string;
      type: any;
      addChild(node:FileNode):void {
        this.kids.push(node);
        this.children.next(this.kids);
      }
      addchildren(nodes:FileNode[]) {
        this.kids = this.kids.concat(this.kids, nodes);
        this.children.next(this.kids);
      }
    }
    
    现在,Material Tree确实检测到了我在孩子身上的变化,并进行了自我更新。 工作示例

    完整、更新的ts文件:

    import {NestedTreeControl} from '@angular/cdk/tree';
    import {Component, Injectable} from '@angular/core';
    import {MatTreeNestedDataSource} from '@angular/material/tree';
    import {BehaviorSubject} from 'rxjs';
    
    /**
     * Json node data with nested structure. Each node has a filename and a value or a list of children
     */
    export class FileNode {
      kids: FileNode[] = [];
      children:BehaviorSubject<FileNode[]> = new BehaviorSubject<FileNode[]>(this.kids);
      filename: string;
      type: any;
      addChild(node:FileNode):void {
        this.kids.push(node);
        this.children.next(this.kids);
      }
      addchildren(nodes:FileNode[]) {
        this.kids = this.kids.concat(this.kids, nodes);
        this.children.next(this.kids);
      }
    }
    
    /**
     * The Json tree data in string. The data could be parsed into Json object
     */
    const TREE_DATA = JSON.stringify({
      Applications: {
        Calendar: 'app',
        Chrome: 'app',
        Webstorm: 'app'
      },
      Documents: {
        angular: {
          src: {
            compiler: 'ts',
            core: 'ts'
          }
        },
        material2: {
          src: {
            button: 'ts',
            checkbox: 'ts',
            input: 'ts'
          }
        }
      },
      Downloads: {
        October: 'pdf',
        November: 'pdf',
        Tutorial: 'html'
      },
      Pictures: {
        'Photo Booth Library': {
          Contents: 'dir',
          Pictures: 'dir'
        },
        Sun: 'png',
        Woods: 'jpg'
      }
    });
    
    /**
     * File database, it can build a tree structured Json object from string.
     * Each node in Json object represents a file or a directory. For a file, it has filename and type.
     * For a directory, it has filename and children (a list of files or directories).
     * The input will be a json object string, and the output is a list of `FileNode` with nested
     * structure.
     */
    @Injectable()
    export class FileDatabase {
      dataChange = new BehaviorSubject<FileNode[]>([]);
    
      get data(): FileNode[] { return this.dataChange.value; }
    
      constructor() {
        this.initialize();
      }
    
      initialize() {
        // Parse the string to json object.
        const dataObject = JSON.parse(TREE_DATA);
    
        // Build the tree nodes from Json object. The result is a list of `FileNode` with nested
        //     file node as children.
        const data = this.buildFileTree(dataObject, 0);
    
        // Notify the change.
        this.dataChange.next(data);
      }
    
      /**
       * Build the file structure tree. The `value` is the Json object, or a sub-tree of a Json object.
       * The return value is the list of `FileNode`.
       */
      buildFileTree(obj: {[key: string]: any}, level: number): FileNode[] {
        return Object.keys(obj).reduce<FileNode[]>((accumulator, key) => {
          const value = obj[key];
          const node = new FileNode();
          node.filename = key;
    
          if (value != null) {
            if (typeof value === 'object') {
              node.addchildren(this.buildFileTree(value, level + 1));
            } else {
              node.type = value;
            }
          }
    
          return accumulator.concat(node);
        }, []);
      }
        addPictureFile():void {
        var picNode = this.data.find((node) => node.filename == 'Pictures');
        var newNode = new FileNode();
        newNode.filename = 'foo';
        newNode.type = 'gif';
        picNode.addChild(newNode);
      }
    }
    
    /**
     * @title Tree with nested nodes
     */
    @Component({
      selector: 'tree-nested-overview-example',
      templateUrl: 'tree-nested-overview-example.html',
      styleUrls: ['tree-nested-overview-example.css'],
      providers: [FileDatabase]
    })
    export class TreeNestedOverviewExample {
      nestedTreeControl: NestedTreeControl<FileNode>;
      nestedDataSource: MatTreeNestedDataSource<FileNode>;
    
      constructor(private database: FileDatabase) {
        this.nestedTreeControl = new NestedTreeControl<FileNode>(this._getChildren);
        this.nestedDataSource = new MatTreeNestedDataSource();
    
        database.dataChange.subscribe(data => {
        this.nestedDataSource.data = data;
        }
        );
      }
    
      hasNestedChild = (_: number, nodeData: FileNode) => !nodeData.type;
    
      private _getChildren = (node: FileNode) => node.children;
    }
    
    从'@angular/cdk/tree'导入{NestedTreeControl};
    从“@angular/core”导入{Component,Injectable};
    从“@angular/material/tree”导入{MatTreeNestedDataSource};
    从“rxjs”导入{BehaviorSubject};
    /**
    *具有嵌套结构的Json节点数据。每个节点都有一个文件名和一个值或子节点列表
    */
    导出类文件节点{
    子节点:FileNode[]=[];
    children:BehaviorSubject=新的BehaviorSubject(this.children);
    文件名:字符串;
    类型:任意;
    addChild(节点:FileNode):无效{
    this.kids.push(节点);
    这个。孩子。下一个(这个。孩子);
    }
    addchildren(节点:FileNode[]){
    this.kids=this.kids.concat(this.kids,节点);
    这个。孩子。下一个(这个。孩子);
    }
    }
    /**
    *字符串形式的Json树数据。数据可以解析为Json对象
    */
    const TREE_DATA=JSON.stringify({
    应用程序:{
    日历:“应用程序”,
    Chrome:“应用程序”,
    Webstorm:“应用程序”
    },
    文件:{
    角度:{
    src:{
    编译器:“ts”,
    核心:“ts”
    }
    },
    材料2:{
    src:{
    按钮:“ts”,
    复选框:“ts”,
    输入:“ts”
    }
    }
    },
    下载:{
    十月:"pdf",,
    十一月:"pdf",,
    教程:“html”
    },
    图片:{
    ‘摄影棚图书馆’:{
    目录:'dir',
    图片:“dir”
    },
    孙:"png",,
    伍兹:“jpg”
    }
    });
    /**
    *文件数据库,它可以从字符串构建树结构的Json对象。
    *Json对象中的每个节点表示一个文件或一个目录。对于文件,它具有文件名和类型。
    *对于目录,它有文件名和子目录(文件或目录的列表)。
    *输入为json对象字符串,输出为带有嵌套
    *结构。
    */
    @可注射()
    导出类文件数据库{
    dataChange=新的行为主体([]);
    get data():FileNode[]{返回this.dataChange.value;}
    构造函数(){
    这是初始化();
    }
    初始化(){
    //将字符串解析为json对象。
    const dataObject=JSON.parse(树数据);
    //从Json对象构建树节点。结果是带有嵌套
    //文件节点作为子节点。
    const data=this.buildFileTree(数据对象,0);
    //通知变更。
    this.dataChange.next(数据);
    }
    /
    
    import {NestedTreeControl} from '@angular/cdk/tree';
    import {Component, Injectable} from '@angular/core';
    import {MatTreeNestedDataSource} from '@angular/material/tree';
    import {BehaviorSubject} from 'rxjs';
    
    /**
     * Json node data with nested structure. Each node has a filename and a value or a list of children
     */
    export class FileNode {
      kids: FileNode[] = [];
      children:BehaviorSubject<FileNode[]> = new BehaviorSubject<FileNode[]>(this.kids);
      filename: string;
      type: any;
      addChild(node:FileNode):void {
        this.kids.push(node);
        this.children.next(this.kids);
      }
      addchildren(nodes:FileNode[]) {
        this.kids = this.kids.concat(this.kids, nodes);
        this.children.next(this.kids);
      }
    }
    
    /**
     * The Json tree data in string. The data could be parsed into Json object
     */
    const TREE_DATA = JSON.stringify({
      Applications: {
        Calendar: 'app',
        Chrome: 'app',
        Webstorm: 'app'
      },
      Documents: {
        angular: {
          src: {
            compiler: 'ts',
            core: 'ts'
          }
        },
        material2: {
          src: {
            button: 'ts',
            checkbox: 'ts',
            input: 'ts'
          }
        }
      },
      Downloads: {
        October: 'pdf',
        November: 'pdf',
        Tutorial: 'html'
      },
      Pictures: {
        'Photo Booth Library': {
          Contents: 'dir',
          Pictures: 'dir'
        },
        Sun: 'png',
        Woods: 'jpg'
      }
    });
    
    /**
     * File database, it can build a tree structured Json object from string.
     * Each node in Json object represents a file or a directory. For a file, it has filename and type.
     * For a directory, it has filename and children (a list of files or directories).
     * The input will be a json object string, and the output is a list of `FileNode` with nested
     * structure.
     */
    @Injectable()
    export class FileDatabase {
      dataChange = new BehaviorSubject<FileNode[]>([]);
    
      get data(): FileNode[] { return this.dataChange.value; }
    
      constructor() {
        this.initialize();
      }
    
      initialize() {
        // Parse the string to json object.
        const dataObject = JSON.parse(TREE_DATA);
    
        // Build the tree nodes from Json object. The result is a list of `FileNode` with nested
        //     file node as children.
        const data = this.buildFileTree(dataObject, 0);
    
        // Notify the change.
        this.dataChange.next(data);
      }
    
      /**
       * Build the file structure tree. The `value` is the Json object, or a sub-tree of a Json object.
       * The return value is the list of `FileNode`.
       */
      buildFileTree(obj: {[key: string]: any}, level: number): FileNode[] {
        return Object.keys(obj).reduce<FileNode[]>((accumulator, key) => {
          const value = obj[key];
          const node = new FileNode();
          node.filename = key;
    
          if (value != null) {
            if (typeof value === 'object') {
              node.addchildren(this.buildFileTree(value, level + 1));
            } else {
              node.type = value;
            }
          }
    
          return accumulator.concat(node);
        }, []);
      }
        addPictureFile():void {
        var picNode = this.data.find((node) => node.filename == 'Pictures');
        var newNode = new FileNode();
        newNode.filename = 'foo';
        newNode.type = 'gif';
        picNode.addChild(newNode);
      }
    }
    
    /**
     * @title Tree with nested nodes
     */
    @Component({
      selector: 'tree-nested-overview-example',
      templateUrl: 'tree-nested-overview-example.html',
      styleUrls: ['tree-nested-overview-example.css'],
      providers: [FileDatabase]
    })
    export class TreeNestedOverviewExample {
      nestedTreeControl: NestedTreeControl<FileNode>;
      nestedDataSource: MatTreeNestedDataSource<FileNode>;
    
      constructor(private database: FileDatabase) {
        this.nestedTreeControl = new NestedTreeControl<FileNode>(this._getChildren);
        this.nestedDataSource = new MatTreeNestedDataSource();
    
        database.dataChange.subscribe(data => {
        this.nestedDataSource.data = data;
        }
        );
      }
    
      hasNestedChild = (_: number, nodeData: FileNode) => !nodeData.type;
    
      private _getChildren = (node: FileNode) => node.children;
    }