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

Commit a0eb661

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
1 parent feec37b commit a0eb661

22 files changed

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

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

Whitespace-only changes.

0 commit comments

Comments
 (0)