Skip to content

Commit

Permalink
refactor(tree):clean up flat tree example
Browse files Browse the repository at this point in the history
clean up flat tree example and use element to update doc site
  • Loading branch information
Vivian Hu committed Dec 6, 2018
1 parent 63be232 commit 8742959
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 295 deletions.
3 changes: 2 additions & 1 deletion src/dev-app/tree/tree-demo-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand All @@ -39,6 +39,7 @@ import {LoadmoreTreeDemo} from './loadmore-tree-demo/loadmore-tree-demo';
MatInputModule,
MatTreeModule,
MatProgressBarModule,
ExamplePageModule,
],
declarations: [
ChecklistNestedTreeDemo,
Expand Down
49 changes: 9 additions & 40 deletions src/dev-app/tree/tree-demo.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
<mat-accordion class="demo-tree-container">

<mat-expansion-panel>
<mat-expansion-panel-header>Flattened tree</mat-expansion-panel-header>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle matTreeNodePadding>
<button mat-icon-button disabled></button>
{{node.filename}} : {{node.type}}
</mat-tree-node>
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + node.filename">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.filename}} : {{node.type}}
</mat-tree-node>
</mat-tree>
<mat-expansion-panel-header>Flat tree</mat-expansion-panel-header>
<material-example id="tree-flat-overview"></material-example>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>CDK Flat tree</mat-expansion-panel-header>
<material-example id="cdk-tree-flat"></material-example>
</mat-expansion-panel>

<mat-expansion-panel>
Expand All @@ -25,7 +14,7 @@
<mat-nested-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node">
<button mat-icon-button disabled></button>
{{node.filename}}: {{node.type}}
{{node.filename}}: {{node.type}}
</li>
</mat-nested-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
Expand All @@ -47,32 +36,12 @@
</mat-tree>
</mat-expansion-panel>

<mat-expansion-panel>
<mat-expansion-panel-header>CDK Flattened tree</mat-expansion-panel-header>
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="demo-tree-node">
<button mat-icon-button disabled></button>
{{node.filename}}: {{node.type}}
</cdk-tree-node>
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
class="demo-tree-node">
<button mat-icon-button [attr.aria-label]="'toggle ' + node.filename"
cdkTreeNodeToggle>
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.filename}}: {{node.type}}
</cdk-tree-node>
</cdk-tree>
</mat-expansion-panel>

<mat-expansion-panel>
<mat-expansion-panel-header>CDK Nested tree</mat-expansion-panel-header>
<cdk-tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl">
<cdk-nested-tree-node *cdkTreeNodeDef="let node" class="demo-tree-node">
<button mat-icon-button disabled></button>
{{node.filename}}: {{node.type}}
{{node.filename}}: {{node.type}}
</cdk-nested-tree-node>
<cdk-nested-tree-node *cdkTreeNodeDef="let node; when: hasNestedChild" class="demo-tree-node">
<button mat-icon-button [attr.aria-label]="'toggle ' + node.filename"
Expand All @@ -81,7 +50,7 @@
{{nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.filename}}: {{node.type}}
{{node.filename}}: {{node.type}}
<div [class.demo-tree-invisible]="!nestedTreeControl.isExpanded(node)"
class="demo-tree-nested-node">
<ng-container cdkTreeNodeOutlet></ng-container>
Expand Down
16 changes: 9 additions & 7 deletions src/lib/tree/data-source/flat-data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class MatTreeFlattener<T, F> {
constructor(public transformFunction: (node: T, level: number) => F,
public getLevel: (node: F) => number,
public isExpandable: (node: F) => boolean,
public getChildren: (node: T) => Observable<T[]> | T[]) {}
public getChildren: (node: T) => Observable<T[]> | T[] | undefined) {}

_flattenNode(node: T, level: number,
resultNodes: F[], parentMap: boolean[]): F[] {
Expand All @@ -59,12 +59,14 @@ export class MatTreeFlattener<T, F> {

if (this.isExpandable(flatNode)) {
const childrenNodes = this.getChildren(node);
if (Array.isArray(childrenNodes)) {
this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
} else {
childrenNodes.pipe(take(1)).subscribe(children => {
this._flattenChildren(children, level, resultNodes, parentMap);
});
if (childrenNodes) {
if (Array.isArray(childrenNodes)) {
this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
} else {
childrenNodes.pipe(take(1)).subscribe(children => {
this._flattenChildren(children, level, resultNodes, parentMap);
});
}
}
}
return resultNodes;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<cdk-tree [dataSource]="dataSource" [treeControl]="treeControl">
<cdk-tree-node *cdkTreeNodeDef="let node" cdkTreeNodePadding class="example-tree-node">
<button mat-icon-button disabled></button>
{{node.filename}}: {{node.type}}
{{node.name}}
</cdk-tree-node>
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding class="example-tree-node">
<button mat-icon-button [attr.aria-label]="'toggle ' + node.filename" cdkTreeNodeToggle>
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.filename}}: {{node.type}}
{{node.name}}
</cdk-tree-node>
</cdk-tree>
174 changes: 52 additions & 122 deletions src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts
Original file line number Diff line number Diff line change
@@ -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 optional list of children.
*/
export class FileNode {
children: FileNode[];
filename: string;
type: any;
interface FoodNode {
name: string;
children?: FoodNode[];
}

/** 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'
const TREE_DATA2: 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' },
]
},
]
},
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.children = this.buildFileTree(value, level + 1);
} else {
node.type = value;
}
}
];

return accumulator.concat(node);
}, []);
}
/** Flat node with expandable and level information */
interface ExampleFlatNode {
expandable: boolean;
name: string;
level: number;
}

/**
Expand All @@ -117,33 +53,27 @@ 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<FileFlatNode>;
treeFlattener: MatTreeFlattener<FileNode, FileFlatNode>;
dataSource: MatTreeFlatDataSource<FileNode, FileFlatNode>;

constructor(database: FileDatabase) {
this.treeFlattener = new MatTreeFlattener(this.transformer, this._getLevel,
this._isExpandable, this._getChildren);
this.treeControl = new FlatTreeControl<FileFlatNode>(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,
name: node.name,
level: level,
};
}

hasChild = (_: number, _nodeData: FileFlatNode) => _nodeData.expandable;
treeControl = new FlatTreeControl<ExampleFlatNode>(
node => node.level, node => node.expandable);

transformer = (node: FileNode, level: number) => {
return new FileFlatNode(!!node.children, node.filename, level, node.type);
}
treeFlattener = new MatTreeFlattener(
this._transformer, node => node.level, node => node.expandable, node => node.children);

private _getLevel = (node: FileFlatNode) => node.level;
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener, TREE_DATA2);

private _isExpandable = (node: FileFlatNode) => node.expandable;
constructor() {
this.dataSource.data = TREE_DATA2;
}

private _getChildren = (node: FileNode): Observable<FileNode[]> => observableOf(node.children);
hasChild = (_: number, node: ExampleFlatNode) => node.expandable;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle matTreeNodePadding>
<button mat-icon-button disabled></button>
{{node.filename}} : {{node.type}}
{{node.name}}
</mat-tree-node>

<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + node.filename">
[attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.filename}} : {{node.type}}
{{node.name}}
</mat-tree-node>
</mat-tree>


<!-- Copyright 2018 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license -->
Loading

0 comments on commit 8742959

Please sign in to comment.