diff --git a/src/cdk/tree/tree.md b/src/cdk/tree/tree.md
index 62835fac659d..3651dcfc5f7e 100644
--- a/src/cdk/tree/tree.md
+++ b/src/cdk/tree/tree.md
@@ -7,6 +7,9 @@ these two types of trees.
#### Flat tree
+
+
+
In a flat tree, the hierarchy is flattened; nodes are not rendered inside of each other, but instead
are rendered as siblings in sequence. An instance of `TreeFlattener` is used to generate the flat
list of items from hierarchical data. The "level" of each tree node is read through the `getLevel`
@@ -28,6 +31,8 @@ variations, such as infinite or virtual scrolling.
#### Nested tree
+
+
In nested tree, children nodes are placed inside their parent node in DOM. The parent node contains
a node outlet into which children are projected.
diff --git a/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.css b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.css
new file mode 100644
index 000000000000..775f480239de
--- /dev/null
+++ b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.css
@@ -0,0 +1,4 @@
+.demo-tree-node {
+ display: flex;
+ align-items: center;
+}
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
new file mode 100644
index 000000000000..efab0bfec51c
--- /dev/null
+++ b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.html
@@ -0,0 +1,12 @@
+
+
+
+ {{node.filename}}: {{node.type}}
+
+
+
+ {{node.filename}}: {{node.type}}
+
+
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
new file mode 100644
index 000000000000..a2361760d279
--- /dev/null
+++ b/src/material-examples/cdk-tree-flat/cdk-tree-flat-example.ts
@@ -0,0 +1,162 @@
+import {Component, Injectable} from '@angular/core';
+import {FlatTreeControl} from '@angular/cdk/tree';
+import {MatTreeFlattener, MatTreeFlatDataSource} from '@angular/material/tree';
+import {of} from 'rxjs/observable/of';
+import {Observable} from 'rxjs/Observable';
+import {BehaviorSubject} from 'rxjs/BehaviorSubject';
+
+/**
+ * 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;
+}
+
+/** Flat node with expandable and level information */
+export class FileFlatNode {
+ filename: string;
+ type: any;
+ level: number;
+ expandable: boolean;
+}
+
+/**
+ * The file structure tree data in string. The data could be parsed into a Json object
+ */
+const TREE_DATA = `
+ {
+ "Documents": {
+ "angular": {
+ "src": {
+ "core": "ts",
+ "compiler": "ts"
+ }
+ },
+ "material2": {
+ "src": {
+ "button": "ts",
+ "checkbox": "ts",
+ "input": "ts"
+ }
+ }
+ },
+ "Downloads": {
+ "Tutorial": "html",
+ "November": "pdf",
+ "October": "pdf"
+ },
+ "Pictures": {
+ "Sun": "png",
+ "Woods": "jpg",
+ "Photo Booth Library": {
+ "Contents": "dir",
+ "Pictures": "dir"
+ }
+ },
+ "Applications": {
+ "Chrome": "app",
+ "Calendar": "app",
+ "Webstorm": "app"
+ }
+}`;
+
+/**
+ * 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: BehaviorSubject = 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(value: any, level: number): FileNode[] {
+ let data: any[] = [];
+ for (let k in value) {
+ let v = value[k];
+ let node = new FileNode();
+ node.filename = `${k}`;
+ if (v === null || v === undefined) {
+ // no action
+ } else if (typeof v === 'object') {
+ node.children = this.buildFileTree(v, level + 1);
+ } else {
+ node.type = v;
+ }
+ data.push(node);
+ }
+ return data;
+ }
+}
+
+/**
+ * @title Tree with flat nodes
+ */
+@Component({
+ 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;
+
+ 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;
+ });
+ }
+
+ transformer = (node: FileNode, level: number) => {
+ let flatNode = new FileFlatNode();
+ flatNode.filename = node.filename;
+ flatNode.type = node.type;
+ flatNode.level = level;
+ flatNode.expandable = !!node.children;
+ return flatNode;
+ }
+
+ private _getLevel = (node: FileFlatNode) => { return node.level; };
+
+ private _isExpandable = (node: FileFlatNode) => { return node.expandable; };
+
+ private _getChildren = (node: FileNode): Observable => { return of(node.children); };
+
+ hasChild = (_: number, _nodeData: FileFlatNode) => { return _nodeData.expandable; };
+}
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
new file mode 100644
index 000000000000..ca6636073bca
--- /dev/null
+++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.css
@@ -0,0 +1,15 @@
+.example-tree-invisible {
+ display: none;
+}
+
+.example-tree ul,
+.example-tree li {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+.example-tree-node {
+ display: block;
+ 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
new file mode 100644
index 000000000000..9a26d39b0833
--- /dev/null
+++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.html
@@ -0,0 +1,15 @@
+
+
+
+ {{node.filename}}: {{node.type}}
+
+
+
+ {{node.filename}}: {{node.type}}
+
+
+
+
+
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
new file mode 100644
index 000000000000..97d5392a09c2
--- /dev/null
+++ b/src/material-examples/cdk-tree-nested/cdk-tree-nested-example.ts
@@ -0,0 +1,132 @@
+import {Component, Injectable} from '@angular/core';
+import {NestedTreeControl} from '@angular/cdk/tree';
+import {MatTreeNestedDataSource} from '@angular/material/tree';
+import {of} from 'rxjs/observable/of';
+import {BehaviorSubject} from 'rxjs/BehaviorSubject';
+
+/**
+ * Json node data with nested structure. Each node has a filename and a value or a list of children
+ */
+export class FileNode {
+ children: FileNode[];
+ filename: string;
+ type: any;
+}
+
+/**
+ * The Json tree data in string. The data could be parsed into Json object
+ */
+const TREE_DATA = `
+ {
+ "Documents": {
+ "angular": {
+ "src": {
+ "core": "ts",
+ "compiler": "ts"
+ }
+ },
+ "material2": {
+ "src": {
+ "button": "ts",
+ "checkbox": "ts",
+ "input": "ts"
+ }
+ }
+ },
+ "Downloads": {
+ "Tutorial": "html",
+ "November": "pdf",
+ "October": "pdf"
+ },
+ "Pictures": {
+ "Sun": "png",
+ "Woods": "jpg",
+ "Photo Booth Library": {
+ "Contents": "dir",
+ "Pictures": "dir"
+ }
+ },
+ "Applications": {
+ "Chrome": "app",
+ "Calendar": "app",
+ "Webstorm": "app"
+ }
+ }`;
+
+/**
+ * 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: BehaviorSubject = 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(value: any, level: number): FileNode[] {
+ let data: any[] = [];
+ for (let k in value) {
+ let v = value[k];
+ let node = new FileNode();
+ node.filename = `${k}`;
+ if (v === null || v === undefined) {
+ // no action
+ } else if (typeof v === 'object') {
+ node.children = this.buildFileTree(v, level + 1);
+ } else {
+ node.type = v;
+ }
+ data.push(node);
+ }
+ return data;
+ }
+}
+
+/**
+ * @title Tree with nested nodes
+ */
+@Component({
+ 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;
+
+ constructor(database: FileDatabase) {
+ this.nestedTreeControl = new NestedTreeControl(this._getChildren);
+ this.nestedDataSource = new MatTreeNestedDataSource();
+
+ database.dataChange.subscribe(data => this.nestedDataSource.data = data);
+ }
+
+ private _getChildren = (node: FileNode) => { return of(node.children); };
+
+ hasNestedChild = (_: number, nodeData: FileNode) => {return !(nodeData.type); };
+}
diff --git a/src/material-examples/tree-flat-overview/tree-flat-overview-example.css b/src/material-examples/tree-flat-overview/tree-flat-overview-example.css
index 138500bdf17a..e69de29bb2d1 100644
--- a/src/material-examples/tree-flat-overview/tree-flat-overview-example.css
+++ b/src/material-examples/tree-flat-overview/tree-flat-overview-example.css
@@ -1,6 +0,0 @@
-.example-tree ul,
-.example-tree li {
- -webkit-margin-before: 0;
- -webkit-margin-after: 0;
- list-style-type: none;
-}
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 0a24659edaaa..a9165cedb2ef 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,5 +1,6 @@
-
+
+
{{node.filename}} : {{node.type}}
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 86f86a8b2742..44db6b054244 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
@@ -26,7 +26,7 @@ export class FileFlatNode {
/**
* The file structure tree data in string. The data could be parsed into a Json object
*/
-const TREE_DATA = `{"Tina":
+const TREE_DATA = `
{
"Documents": {
"angular": {
@@ -61,7 +61,7 @@ const TREE_DATA = `{"Tina":
"Calendar": "app",
"Webstorm": "app"
}
-}}`;
+}`;
/**
* File database, it can build a tree structured Json object from string.
@@ -96,7 +96,7 @@ export class FileDatabase {
* 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(value: any, level: number) {
+ buildFileTree(value: any, level: number): FileNode[] {
let data: any[] = [];
for (let k in value) {
let v = value[k];
diff --git a/src/material-examples/tree-nested-overview/tree-nested-overview-example.css b/src/material-examples/tree-nested-overview/tree-nested-overview-example.css
index 1bcbfb831ce1..3cbc799e0492 100644
--- a/src/material-examples/tree-nested-overview/tree-nested-overview-example.css
+++ b/src/material-examples/tree-nested-overview/tree-nested-overview-example.css
@@ -4,7 +4,7 @@
.example-tree ul,
.example-tree li {
- -webkit-margin-before: 0;
- -webkit-margin-after: 0;
+ margin-top: 0;
+ margin-bottom: 0;
list-style-type: none;
}
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 efe21202abaf..0cf052680538 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,7 +1,8 @@
-
-
{{node.filename}}: {{node.type}}
+
+
+ {{node.filename}}: {{node.type}}
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 6a80f1d4c720..804a853a6e8e 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
@@ -16,7 +16,7 @@ export class FileNode {
/**
* The Json tree data in string. The data could be parsed into Json object
*/
-const TREE_DATA = `{"Tina":
+const TREE_DATA = `
{
"Documents": {
"angular": {
@@ -51,7 +51,7 @@ const TREE_DATA = `{"Tina":
"Calendar": "app",
"Webstorm": "app"
}
-}}`;
+ }`;
/**
* File database, it can build a tree structured Json object from string.
@@ -86,7 +86,7 @@ export class FileDatabase {
* 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(value: any, level: number) {
+ buildFileTree(value: any, level: number): FileNode[] {
let data: any[] = [];
for (let k in value) {
let v = value[k];