Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 9ee236e

Browse files
committed
docs:(cookbook showing how to create a TreeView)
working on getting tree view rendering wiring up tree more features styles added add/cancel styles http fixed styling added error handling docs clean-up starting article img text updated e2e text text text renamed rating fixed test typo update to rc 1 shim lint
1 parent b669e30 commit 9ee236e

22 files changed

+565
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/// <reference path='../_protractor/e2e.d.ts' />
2+
'use strict';
3+
/* tslint:disable:quotemark */
4+
describe('Tree View', function () {
5+
6+
beforeEach(function () {
7+
browser.get('');
8+
});
9+
10+
it('should expand and collapse all nodes', function(){
11+
let expandAll = element(by.xpath('//button[text()="Expand All"]'));
12+
let collapseAll = element(by.xpath('//button[text()="Collapse All"]'));
13+
14+
expandAll.click()
15+
.then(function(){
16+
expect(findHeroCount('Dr IQ')).toBe(1);
17+
expect(findHeroCount('Bombasto')).toBe(1);
18+
expect(findHeroCount('Celeritas')).toBe(1);
19+
expect(findHeroCount('RubberMan')).toBe(1);
20+
expect(findHeroCount('Tornado')).toBe(1);
21+
expect(findHeroCount('Dynama')).toBe(2);
22+
expect(findHeroCount('Magma')).toBe(1);
23+
});
24+
25+
collapseAll.click()
26+
.then(function(){
27+
expect(findHeroCount('Dr IQ')).toBe(0);
28+
expect(findHeroCount('Bombasto')).toBe(0);
29+
expect(findHeroCount('Celeritas')).toBe(0);
30+
expect(findHeroCount('RubberMan')).toBe(0);
31+
expect(findHeroCount('Tornado')).toBe(0);
32+
expect(findHeroCount('Dynama')).toBe(0);
33+
expect(findHeroCount('Magma')).toBe(0);
34+
});
35+
});
36+
37+
function findHeroCount(name: string) {
38+
let length = element.all(by.xpath('//div[text()="Name: ' + name + '"]')).count();
39+
return length;
40+
}
41+
42+
it('should add hero', function () {
43+
let usaNode = element.all(by.xpath('//a[text()="USA"]')).get(0);
44+
45+
usaNode.click().then(function() {
46+
let name = element(by.xpath('//input[@placeholder="name"]'));
47+
48+
let rating = element(by.xpath('//input[@placeholder="ranking"]'));
49+
50+
name.sendKeys('New Hero');
51+
rating.sendKeys('10');
52+
53+
let addButton = element(by.xpath('//button[text()="Add Hero"]'));
54+
return addButton.click();
55+
})
56+
.then(function(){
57+
let name = element(by.xpath('//div[text()="name: New Hero"]'));
58+
expect(name).toBeDefined();
59+
60+
let rating = element(by.xpath('//div[text()="10"]'));
61+
expect(rating).toBeDefined();
62+
});
63+
});
64+
65+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/*.js
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- #docregion -->
2+
<input placeholder="name" [(ngModel)]="hero.name" />
3+
<input placeholder="ranking" type="number" [(ngModel)]="hero.ranking" />
4+
<div>
5+
<button (click)="addHero()">Add Hero</button>
6+
<button (click)="cancel()">Cancel</button>
7+
</div>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// #docregion
2+
import { Component, OnInit } from '@angular/core';
3+
4+
import { TreeNodeService } from './tree-node.service';
5+
import { Hero } from './hero';
6+
7+
@Component({
8+
selector: 'add-hero',
9+
templateUrl: 'app/add-hero.component.html'
10+
})
11+
export class AddHeroComponent implements OnInit {
12+
13+
hero: Hero;
14+
15+
constructor(private treeNodeService: TreeNodeService) {
16+
}
17+
18+
addHero() {
19+
if (this.hero.name) {
20+
this.treeNodeService.addHero(this.hero);
21+
this.hero = new Hero();
22+
}
23+
}
24+
25+
cancel() {
26+
this.treeNodeService.selectedNode.unselect();
27+
}
28+
29+
ngOnInit() {
30+
this.hero = new Hero();
31+
}
32+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// #docregion
2+
import { Component, OnInit } from '@angular/core';
3+
4+
import { TreeViewComponent } from './tree-view.component';
5+
import { TreeNode } from './tree-node';
6+
import { TreeNodeService } from './tree-node.service';
7+
8+
@Component({
9+
selector: 'my-app',
10+
template: `
11+
<div>
12+
<h2>Hero locations</h2>
13+
<button (click)="_treeNodeService.toggleNodes(_nodes,true)">Expand All</button>
14+
<button (click)="_treeNodeService.toggleNodes(_nodes,false)">Collapse All</button>
15+
<tree-view id="heroes" [nodes]="_nodes"></tree-view>
16+
</div>
17+
`,
18+
directives: [TreeViewComponent],
19+
providers: [TreeNodeService]
20+
})
21+
export class AppComponent implements OnInit {
22+
23+
private _nodes: Array<TreeNode> = [];
24+
25+
constructor(private _treeNodeService: TreeNodeService) {
26+
}
27+
28+
ngOnInit() {
29+
this._treeNodeService
30+
.getTreeNodes()
31+
.then((nodes: Array<TreeNode>) => this._nodes = nodes)
32+
.catch((error: any) => console.log(error)); // TODO: Display error
33+
}
34+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!-- #docregion -->
2+
<div class="hero-node" [ngClass]="heroClass" >
3+
<div>Name: {{hero.name}}</div>
4+
<div>Ranking: {{hero.ranking}}</div>
5+
</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// #docregion
2+
import { Component, Input, OnInit } from '@angular/core';
3+
4+
import { Hero } from './hero';
5+
6+
@Component({
7+
selector: 'hero-node',
8+
templateUrl: 'app/hero-node.component.html'
9+
})
10+
export class HeroNodeComponent implements OnInit {
11+
@Input() hero: Hero;
12+
heroClass: string;
13+
14+
ngOnInit() {
15+
if (this.hero.ranking > 7) {
16+
this.heroClass = 'hero-top';
17+
}else if (this.hero.ranking > 4) {
18+
this.heroClass = 'hero-ok';
19+
}else {
20+
this.heroClass = 'hero-low';
21+
}
22+
}
23+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// #docregion
2+
export class Hero {
3+
4+
constructor(public name?: string, public ranking?: number) {
5+
}
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// #docregion
2+
import { bootstrap } from '@angular/platform-browser-dynamic';
3+
4+
import { AppComponent } from './app.component';
5+
import { HTTP_PROVIDERS } from '@angular/http';
6+
7+
import 'rxjs/Rx';
8+
9+
bootstrap(AppComponent, [HTTP_PROVIDERS])
10+
.catch((err: any) => console.error(err));
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"nodes":[
3+
{
4+
"title":"USA",
5+
"nodes":[
6+
{
7+
"title":"New York City",
8+
"nodes":[
9+
{"title":"Brooklyn","heroes":[{"name":"Dr IQ","ranking":10}]},
10+
{"title":"Manhattan","heroes":[{"name":"Bombasto","ranking":2}]},
11+
{"title":"Bronx","heroes":[{"name":"Celeritas","ranking":4}]},
12+
{"title":"Queens","heroes":[{"name":"RubberMan","ranking":6}]},
13+
{"title":"Staten Island","heroes":[{"name":"Dynama","ranking":8}]}]
14+
}
15+
]
16+
},
17+
{
18+
"title":"Canada",
19+
"nodes":[
20+
{"title":"Calgary","heroes":[{"name":"Tornado","ranking":3},{"name":"Dynama","ranking":8}]},
21+
{"title":"Ottawa","heroes":[{"name":"Magma","ranking":10}]}
22+
]
23+
}
24+
]
25+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// #docregion
2+
import { Injectable } from '@angular/core';
3+
import { Http } from '@angular/http';
4+
5+
import { TreeNode } from './tree-node';
6+
import { Hero } from './hero';
7+
8+
@Injectable()
9+
export class TreeNodeService {
10+
11+
private _root = new TreeNode('Hero Regions', [], []);
12+
selectedNode: TreeNode;
13+
14+
constructor(private _http: Http) {
15+
}
16+
17+
// #docregion build-tree
18+
private _buildTreeRecursive(root: TreeNode, nodes: Array<any>): TreeNode {
19+
if (nodes) {
20+
nodes.forEach(node => {
21+
let heroes = (node.heroes || []).map((hero: any) => new Hero(hero.name, hero.ranking));
22+
let treeNode = new TreeNode(node.title, [], heroes);
23+
root.nodes.push(this._buildTreeRecursive(treeNode, node.nodes));
24+
return treeNode;
25+
});
26+
}
27+
return root;
28+
}
29+
30+
getTreeNodes(): any {
31+
return this._http.get('./app/mock-data.json')
32+
.toPromise()
33+
.then(res => {
34+
let root = this._buildTreeRecursive(this._root, res.json().nodes);
35+
return root.nodes;
36+
});
37+
}
38+
// #enddocregion build-tree
39+
40+
addHero(newHero: Hero) {
41+
this.selectedNode.heroes.push(newHero);
42+
}
43+
44+
// #docregion toggle-nodes
45+
toggleNodes(nodes: Array<TreeNode>, state: boolean) {
46+
nodes.forEach(node => {
47+
node.expanded = state;
48+
this.toggleNodes(node.nodes, state);
49+
});
50+
}
51+
// #enddocregion toggle-nodes
52+
53+
selectNode(node: TreeNode) {
54+
if (this.selectedNode) {
55+
this.selectedNode.unselect();
56+
}
57+
58+
this.selectedNode = node;
59+
this.selectedNode.select();
60+
}
61+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// #docregion
2+
import { Hero } from './hero';
3+
4+
export class TreeNode {
5+
6+
expanded: boolean = false;
7+
selected: boolean = false;
8+
9+
constructor(public title: string, public nodes?: Array<TreeNode>, public heroes?: Array<Hero>) {
10+
}
11+
12+
getIcon() {
13+
if (this._hasChildren()) {
14+
if (this.expanded) {
15+
return '-';
16+
}
17+
return '+';
18+
}
19+
return '';
20+
}
21+
22+
toggle() {
23+
this.expanded = !this.expanded;
24+
if (this.expanded === false) {
25+
this.selected = false;
26+
}
27+
}
28+
29+
select() {
30+
this.selected = true;
31+
this.expanded = true;
32+
}
33+
34+
unselect() {
35+
this.selected = false;
36+
}
37+
38+
private _hasChildren() {
39+
return (this.nodes.length + this.heroes.length) > 0;
40+
}
41+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!-- #docregion -->
2+
<ul *ngIf="nodes.length > 0">
3+
<li *ngFor="#node of nodes">
4+
<a class="tree-node-icon" (click)="node.toggle()">{{node.getIcon()}}</a>
5+
<a class="hero-location" (click)="select(node)" [ngClass]="{'node-selected':node.selected}">{{node.title}}</a>
6+
<div *ngIf="node.expanded">
7+
<ul>
8+
<li *ngFor="let hero of node.heroes">
9+
<hero-node [hero]="hero"></hero-node>
10+
</li>
11+
<li>
12+
<div class="add-section" *ngIf="node.selected">
13+
<add-hero></add-hero>
14+
</div>
15+
</li>
16+
</ul>
17+
<!--Self reference in the template-->
18+
<tree-view [nodes]="node.nodes"></tree-view>
19+
</div>
20+
</li>
21+
</ul>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// #docregion
2+
import { Component, Input } from '@angular/core';
3+
4+
import { AddHeroComponent } from './add-hero.component';
5+
import { HeroNodeComponent } from './hero-node.component';
6+
import { TreeNode } from './tree-node';
7+
import { TreeNodeService } from './tree-node.service';
8+
9+
@Component({
10+
selector: 'tree-view',
11+
12+
directives: [TreeViewComponent, // Notice: TreeViewComponent reference inside TreeViewComponent
13+
AddHeroComponent,
14+
HeroNodeComponent],
15+
16+
templateUrl: './app/tree-view.component.html'
17+
})
18+
export class TreeViewComponent {
19+
@Input() nodes: Array<TreeNode>;
20+
21+
constructor(private _treeNodeService: TreeNodeService) {
22+
}
23+
24+
select(node: TreeNode) {
25+
this._treeNodeService.selectNode(node);
26+
}
27+
}

public/docs/_examples/cb-tree-view/ts/example-config.json

Whitespace-only changes.

0 commit comments

Comments
 (0)