diff --git a/src/dev-app/tree/tree-demo-module.ts b/src/dev-app/tree/tree-demo-module.ts index 77ccf440578..f1c21a7ae76 100644 --- a/src/dev-app/tree/tree-demo-module.ts +++ b/src/dev-app/tree/tree-demo-module.ts @@ -24,7 +24,7 @@ import {ChecklistTreeDemo} from './checklist-tree-demo/checklist-tree-demo'; import {ChecklistNestedTreeDemo} from './checklist-tree-demo/checklist-nested-tree-demo'; import {DynamicTreeDemo} from './dynamic-tree-demo/dynamic-tree-demo'; import {LoadmoreTreeDemo} from './loadmore-tree-demo/loadmore-tree-demo'; - +import {ExamplePageModule} from '../example/example-module'; @NgModule({ imports: [ @@ -39,6 +39,7 @@ import {LoadmoreTreeDemo} from './loadmore-tree-demo/loadmore-tree-demo'; MatInputModule, MatTreeModule, MatProgressBarModule, + ExamplePageModule, ], declarations: [ ChecklistNestedTreeDemo, diff --git a/src/dev-app/tree/tree-demo.html b/src/dev-app/tree/tree-demo.html index 6e36ea81886..71a89540303 100644 --- a/src/dev-app/tree/tree-demo.html +++ b/src/dev-app/tree/tree-demo.html @@ -1,93 +1,19 @@ - - Flattened tree - - - - {{node.filename}} : {{node.type}} - - - - {{node.filename}} : {{node.type}} - - + Flat tree + + + + CDK Flat tree + - Nested tree - - -
  • - - {{node.filename}}: {{node.type}} -
  • -
    - -
  • -
    - - {{node.filename}} -
    -
      - -
    -
  • -
    -
    +
    - - - CDK Flattened tree - - - - {{node.filename}}: {{node.type}} - - - - {{node.filename}}: {{node.type}} - - - - CDK Nested tree - - - - {{node.filename}}: {{node.type}} - - - - {{node.filename}}: {{node.type}} -
    - -
    -
    -
    +
    @@ -106,7 +32,7 @@ - Loadmore flat tree + Load more flat tree diff --git a/src/dev-app/tree/tree-demo.ts b/src/dev-app/tree/tree-demo.ts index a6f16c80828..f93d303cc2a 100644 --- a/src/dev-app/tree/tree-demo.ts +++ b/src/dev-app/tree/tree-demo.ts @@ -5,72 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - -import {FlatTreeControl, NestedTreeControl} from '@angular/cdk/tree'; import {Component} from '@angular/core'; -import { - MatTreeFlatDataSource, - MatTreeFlattener, - MatTreeNestedDataSource -} from '@angular/material/tree'; -import {FileDatabase, FileFlatNode, FileNode} from './file-database'; - @Component({ moduleId: module.id, selector: 'tree-demo', templateUrl: 'tree-demo.html', styleUrls: ['tree-demo.css'], - providers: [FileDatabase] }) -export class TreeDemo { - // Flat tree control - treeControl: FlatTreeControl; - - // Nested tree control - nestedTreeControl: NestedTreeControl; - - treeFlattener: MatTreeFlattener; - - // Flat tree data source - dataSource: MatTreeFlatDataSource; - - // Nested tree data source - nestedDataSource: MatTreeNestedDataSource; - - constructor(database: FileDatabase) { - this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, - this.isExpandable, this.getChildren); - // For flat tree - this.treeControl = new FlatTreeControl(this.getLevel, this.isExpandable); - this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); - - // For nested tree - this.nestedTreeControl = new NestedTreeControl(this.getChildren); - this.nestedDataSource = new MatTreeNestedDataSource(); - - database.dataChange.subscribe(data => { - this.dataSource.data = data; - this.nestedDataSource.data = data; - }); - } - - transformer = (node: FileNode, level: number) => { - const flatNode = new FileFlatNode(); - flatNode.filename = node.filename; - flatNode.type = node.type; - flatNode.level = level; - flatNode.expandable = !!node.children; - return flatNode; - } - - getLevel = (node: FileFlatNode) => { return node.level; }; - - isExpandable = (node: FileFlatNode) => { return node.expandable; }; - - getChildren = (node: FileNode): FileNode[] => { return node.children; }; - - hasChild = (_: number, _nodeData: FileFlatNode) => { return _nodeData.expandable; }; - - hasNestedChild = (_: number, nodeData: FileNode) => {return !(nodeData.type); }; -} +export class TreeDemo {} diff --git a/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.html b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.html index 1ad37095938..2c874f30a05 100644 --- a/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.html +++ b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.html @@ -1,14 +1,24 @@ - + + + - {{node.filename}}: {{node.type}} + {{node.name}} - - - {{node.filename}}: {{node.type}} + {{node.name}} diff --git a/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts index 2df6c7cb80a..dbd2261d35a 100644 --- a/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts +++ b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts @@ -1,113 +1,62 @@ +import {ArrayDataSource} from '@angular/cdk/collections'; import {FlatTreeControl} from '@angular/cdk/tree'; -import {Component, Injectable} from '@angular/core'; -import {MatTreeFlatDataSource, MatTreeFlattener} from '@angular/material/tree'; -import {BehaviorSubject, Observable, of as observableOf} from 'rxjs'; +import {Component} from '@angular/core'; -/** - * File node data with nested structure. - * Each node has a filename, and a type or a list of children. - */ -export class FileNode { - children: FileNode[]; - filename: string; - type: any; -} + +const TREE_DATA: ExampleFlatNode[] = [ + { + name: 'Fruit', + expandable: true, + level: 0, + }, { + name: 'Apple', + expandable: false, + level: 1, + }, { + name: 'Banana', + expandable: false, + level: 1, + }, { + name: 'Fruit loops', + expandable: false, + level: 1, + }, { + name: 'Vegetables', + expandable: true, + level: 0, + }, { + name: 'Green', + expandable: true, + level: 1, + }, { + name: 'Broccoli', + expandable: false, + level: 2, + }, { + name: 'Brussel sprouts', + expandable: false, + level: 2, + }, { + name: 'Orange', + expandable: true, + level: 1, + }, { + name: 'Pumpkins', + expandable: false, + level: 2, + }, { + name: 'Carrots', + expandable: false, + level: 2, + } +]; /** Flat node with expandable and level information */ -export class FileFlatNode { - constructor( - public expandable: boolean, public filename: string, public level: number, public type: any) {} -} - -/** - * The file structure tree data in string. The data could be parsed into a 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([]); - - 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((accumulator, key) => { - const value = obj[key]; - const node = new FileNode(); - node.filename = key; - - if (value != null) { - if (typeof value === 'object') { - node.children = this.buildFileTree(value, level + 1); - } else { - node.type = value; - } - } - - return accumulator.concat(node); - }, []); - } +interface ExampleFlatNode { + expandable: boolean; + name: string; + level: number; + isExpanded?: boolean; } /** @@ -117,33 +66,29 @@ export class FileDatabase { selector: 'cdk-tree-flat-example', templateUrl: 'cdk-tree-flat-example.html', styleUrls: ['cdk-tree-flat-example.css'], - providers: [FileDatabase] }) export class CdkTreeFlatExample { - treeControl: FlatTreeControl; - treeFlattener: MatTreeFlattener; - dataSource: MatTreeFlatDataSource; + treeControl = new FlatTreeControl( + node => node.level, node => node.expandable); - constructor(database: FileDatabase) { - this.treeFlattener = new MatTreeFlattener(this.transformer, this._getLevel, - this._isExpandable, this._getChildren); - this.treeControl = new FlatTreeControl(this._getLevel, this._isExpandable); - this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + dataSource = new ArrayDataSource(TREE_DATA); - database.dataChange.subscribe(data => { - this.dataSource.data = data; - }); + hasChild = (_: number, node: ExampleFlatNode) => node.expandable; + + getParentNode(node: ExampleFlatNode) { + const nodeIndex = TREE_DATA.indexOf(node); + + for (let i = nodeIndex - 1; i >= 0; i--) { + if (TREE_DATA[i].level === node.level - 1) { + return TREE_DATA[i]; + } + } + + return null; } - hasChild = (_: number, _nodeData: FileFlatNode) => _nodeData.expandable; - - transformer = (node: FileNode, level: number) => { - return new FileFlatNode(!!node.children, node.filename, level, node.type); + shouldRender(node: ExampleFlatNode) { + const parent = this.getParentNode(node); + return !parent || parent.isExpanded; } - - private _getLevel = (node: FileFlatNode) => node.level; - - private _isExpandable = (node: FileFlatNode) => node.expandable; - - private _getChildren = (node: FileNode): Observable => observableOf(node.children); } diff --git a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.css b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.css index ca6636073bc..b879f06d755 100644 --- a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.css +++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.css @@ -8,8 +8,10 @@ margin-bottom: 0; list-style-type: none; } - .example-tree-node { display: block; +} + +.example-tree-node .example-tree-node { padding-left: 40px; } diff --git a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.html b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.html index 1c59e42630c..462822c40e0 100644 --- a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.html +++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.html @@ -1,16 +1,19 @@ - + + + - {{node.filename}}: {{node.type}} + {{node.name}} - - - {{node.filename}}: {{node.type}} -
    + {{node.name}} +
    diff --git a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.ts b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.ts index d574910c8ea..b69b44415c4 100644 --- a/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.ts +++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.ts @@ -1,107 +1,43 @@ +import {ArrayDataSource} from '@angular/cdk/collections'; +import {Component} from '@angular/core'; import {NestedTreeControl} from '@angular/cdk/tree'; -import {Component, Injectable} from '@angular/core'; -import {MatTreeNestedDataSource} from '@angular/material/tree'; -import {BehaviorSubject, of as observableOf} from 'rxjs'; /** - * Json node data with nested structure. Each node has a filename and a value or a list of children + * Food data with nested structure. + * Each node has a name and an optiona list of children. */ -export class FileNode { - children: FileNode[]; - filename: string; - type: any; +interface FoodNode { + name: string; + children?: FoodNode[]; } -/** - * 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' +const TREE_DATA: FoodNode[] = [ + { + name: 'Fruit', + children: [ + {name: 'Apple'}, + {name: 'Banana'}, + {name: 'Fruit loops'}, + ] + }, { + name: 'Vegetables', + children: [ + { + name: 'Green', + children: [ + {name: 'Broccoli'}, + {name: 'Brussel sprouts'}, + ] + }, { + name: 'Orange', + children: [ + {name: 'Pumpkins'}, + {name: 'Carrots'}, + ] + }, + ] }, - 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([]); - - 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((accumulator, key) => { - const value = obj[key]; - const node = new FileNode(); - node.filename = key; - - if (value != null) { - if (typeof value === 'object') { - node.children = this.buildFileTree(value, level + 1); - } else { - node.type = value; - } - } - - return accumulator.concat(node); - }, []); - } -} +]; /** * @title Tree with nested nodes @@ -110,20 +46,10 @@ export class FileDatabase { selector: 'cdk-tree-nested-example', templateUrl: 'cdk-tree-nested-example.html', styleUrls: ['cdk-tree-nested-example.css'], - providers: [FileDatabase] }) export class CdkTreeNestedExample { - nestedTreeControl: NestedTreeControl; - nestedDataSource: MatTreeNestedDataSource; + treeControl = new NestedTreeControl (node => node.children); + dataSource = new ArrayDataSource(TREE_DATA); - constructor(database: FileDatabase) { - this.nestedTreeControl = new NestedTreeControl(this._getChildren); - this.nestedDataSource = new MatTreeNestedDataSource(); - - database.dataChange.subscribe(data => this.nestedDataSource.data = data); - } - - hasNestedChild = (_: number, nodeData: FileNode) => !nodeData.type; - - private _getChildren = (node: FileNode) => observableOf(node.children); + hasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0; } diff --git a/src/material-examples/tree-flat-overview/tree-flat-overview-example.html b/src/material-examples/tree-flat-overview/tree-flat-overview-example.html index a4729f13806..5a28c767051 100644 --- a/src/material-examples/tree-flat-overview/tree-flat-overview-example.html +++ b/src/material-examples/tree-flat-overview/tree-flat-overview-example.html @@ -1,16 +1,18 @@ - + + + - {{node.filename}} : {{node.type}} + {{node.name}} - + - {{node.filename}} : {{node.type}} + {{node.name}} diff --git a/src/material-examples/tree-flat-overview/tree-flat-overview-example.ts b/src/material-examples/tree-flat-overview/tree-flat-overview-example.ts index 0e5155d104f..0f99a7f14ae 100644 --- a/src/material-examples/tree-flat-overview/tree-flat-overview-example.ts +++ b/src/material-examples/tree-flat-overview/tree-flat-overview-example.ts @@ -1,113 +1,49 @@ import {FlatTreeControl} from '@angular/cdk/tree'; -import {Component, Injectable} from '@angular/core'; +import {Component} from '@angular/core'; import {MatTreeFlatDataSource, MatTreeFlattener} from '@angular/material/tree'; -import {BehaviorSubject, Observable, of as observableOf} from 'rxjs'; /** - * File node data with nested structure. - * Each node has a filename, and a type or a list of children. + * Food data with nested structure. + * Each node has a name and an optiona list of children. */ -export class FileNode { - children: FileNode[]; - filename: string; - type: any; +interface FoodNode { + name: string; + children?: FoodNode[]; } +const TREE_DATA: FoodNode[] = [ + { + name: 'Fruit', + children: [ + {name: 'Apple'}, + {name: 'Banana'}, + {name: 'Fruit loops'}, + ] + }, { + name: 'Vegetables', + children: [ + { + name: 'Green', + children: [ + {name: 'Broccoli'}, + {name: 'Brussel sprouts'}, + ] + }, { + name: 'Orange', + children: [ + {name: 'Pumpkins'}, + {name: 'Carrots'}, + ] + }, + ] + }, +]; + /** Flat node with expandable and level information */ -export class FileFlatNode { - constructor( - public expandable: boolean, public filename: string, public level: number, public type: any) {} -} - -/** - * The file structure tree data in string. The data could be parsed into a 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([]); - - 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((accumulator, key) => { - const value = obj[key]; - const node = new FileNode(); - node.filename = key; - - if (value != null) { - if (typeof value === 'object') { - node.children = this.buildFileTree(value, level + 1); - } else { - node.type = value; - } - } - - return accumulator.concat(node); - }, []); - } +interface ExampleFlatNode { + expandable: boolean; + name: string; + level: number; } /** @@ -117,31 +53,27 @@ export class FileDatabase { selector: 'tree-flat-overview-example', templateUrl: 'tree-flat-overview-example.html', styleUrls: ['tree-flat-overview-example.css'], - providers: [FileDatabase] }) export class TreeFlatOverviewExample { - treeControl: FlatTreeControl; - treeFlattener: MatTreeFlattener; - dataSource: MatTreeFlatDataSource; - - constructor(database: FileDatabase) { - this.treeFlattener = new MatTreeFlattener(this.transformer, this._getLevel, - this._isExpandable, this._getChildren); - this.treeControl = new FlatTreeControl(this._getLevel, this._isExpandable); - this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); - - database.dataChange.subscribe(data => this.dataSource.data = data); + private transformer = (node: FoodNode, level: number) => { + return { + expandable: !!node.children && node.children.length > 0, + name: node.name, + level: level, + }; } - transformer = (node: FileNode, level: number) => { - return new FileFlatNode(!!node.children, node.filename, level, node.type); + treeControl = new FlatTreeControl( + node => node.level, node => node.expandable); + + treeFlattener = new MatTreeFlattener( + this.transformer, node => node.level, node => node.expandable, node => node.children); + + dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener); + + constructor() { + this.dataSource.data = TREE_DATA; } - private _getLevel = (node: FileFlatNode) => node.level; - - private _isExpandable = (node: FileFlatNode) => node.expandable; - - private _getChildren = (node: FileNode): Observable => observableOf(node.children); - - hasChild = (_: number, _nodeData: FileFlatNode) => _nodeData.expandable; + hasChild = (_: number, node: ExampleFlatNode) => node.expandable; } diff --git a/src/material-examples/tree-nested-overview/tree-nested-overview-example.html b/src/material-examples/tree-nested-overview/tree-nested-overview-example.html index 646b426877c..b1d3cd003a3 100644 --- a/src/material-examples/tree-nested-overview/tree-nested-overview-example.html +++ b/src/material-examples/tree-nested-overview/tree-nested-overview-example.html @@ -1,23 +1,25 @@ - + +
  • + - {{node.filename}}: {{node.type}} + {{node.name}}
  • - - + +
  • - {{node.filename}} + {{node.name}}
    -
      +
      diff --git a/src/material-examples/tree-nested-overview/tree-nested-overview-example.ts b/src/material-examples/tree-nested-overview/tree-nested-overview-example.ts index 2e93cde5ac4..2e8fb28de4d 100644 --- a/src/material-examples/tree-nested-overview/tree-nested-overview-example.ts +++ b/src/material-examples/tree-nested-overview/tree-nested-overview-example.ts @@ -1,107 +1,43 @@ import {NestedTreeControl} from '@angular/cdk/tree'; -import {Component, Injectable} from '@angular/core'; +import {Component} 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 + * Food data with nested structure. + * Each node has a name and an optiona list of children. */ -export class FileNode { - children: FileNode[]; - filename: string; - type: any; +interface FoodNode { + name: string; + children?: FoodNode[]; } -/** - * 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' +const TREE_DATA: FoodNode[] = [ + { + name: 'Fruit', + children: [ + {name: 'Apple'}, + {name: 'Banana'}, + {name: 'Fruit loops'}, + ] + }, { + name: 'Vegetables', + children: [ + { + name: 'Green', + children: [ + {name: 'Broccoli'}, + {name: 'Brussel sprouts'}, + ] + }, { + name: 'Orange', + children: [ + {name: 'Pumpkins'}, + {name: 'Carrots'}, + ] + }, + ] }, - 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([]); - - 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((accumulator, key) => { - const value = obj[key]; - const node = new FileNode(); - node.filename = key; - - if (value != null) { - if (typeof value === 'object') { - node.children = this.buildFileTree(value, level + 1); - } else { - node.type = value; - } - } - - return accumulator.concat(node); - }, []); - } -} +]; /** * @title Tree with nested nodes @@ -110,20 +46,14 @@ export class FileDatabase { selector: 'tree-nested-overview-example', templateUrl: 'tree-nested-overview-example.html', styleUrls: ['tree-nested-overview-example.css'], - providers: [FileDatabase] }) export class TreeNestedOverviewExample { - nestedTreeControl: NestedTreeControl; - nestedDataSource: MatTreeNestedDataSource; + treeControl = new NestedTreeControl(node => node.children); + dataSource = new MatTreeNestedDataSource(); - constructor(database: FileDatabase) { - this.nestedTreeControl = new NestedTreeControl(this._getChildren); - this.nestedDataSource = new MatTreeNestedDataSource(); - - database.dataChange.subscribe(data => this.nestedDataSource.data = data); + constructor() { + this.dataSource.data = TREE_DATA; } - hasNestedChild = (_: number, nodeData: FileNode) => !nodeData.type; - - private _getChildren = (node: FileNode) => node.children; + hasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0; }