<!DOCTYPE html>
<html>
<head>
<title>ViewChildren ViewChild Sample</title>
<script src="https://code.angularjs.org/2.0.0-beta.15/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="config.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/Rx.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/angular2.dev.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/http.dev.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
### Angular2 Example - ViewChildren, ViewChild, Input, and Output in a Component Heirarchy.
A simple plunker showing usage of a component hierarchy (Parent -> Child -> SubChild)
displayed on the screen multiple times. This helps demonstrate 3 instance of this
hierarchy and the ability of angular2 to keep our connections (inputs, outputs, selectors, etc..)
scoped inside those instances of each parent component.
Contains Angular2 usage of:
- ViewChildren for creating multiple Parent Component.
- ViewChild for nested Child and SubChild components.
- Data driven using spec.json files per parent component.
- Input for passing in urls and spec data to nested components.
- Output for passing synthetic events up the component chain.
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src"
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
}
}
});
// //main entry point
import {bootstrap} from 'angular2/platform/browser'
import {HTTP_PROVIDERS} from 'angular2/http';
import {App} from './app'
import {enableProdMode} from "angular2/core";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
bootstrap(<any>App, [HTTP_PROVIDERS]).catch(err => console.error(err));
import {ApplicationRef, Component, ComponentRef,DynamicComponentLoader, Injector, QueryList, ViewChildren} from 'angular2/core';
import {Parent} from './parent';
import {DataService} from './data.service';
@Component({
selector : 'my-app',
providers : [DataService],
directives : [Parent],
host : {style : 'border: 1px solid black;min-height:20px;display:block;padding:10px;margin:10px;'},
template : `<parent-component *ngFor="#specUrl of specUrls" [specUrl]="specUrl"></parent-component>`
})
export class App
{
// used by the template to create a parent-component element per item in the array.
// each item is then passed as input to it's parent-component
private specUrls:Array<string> = ['./spec1.json', './spec2.json', './spec3.json'];
// uses the Parent type find each parent-component element - i.e. the ViewChildren
@ViewChildren(Parent) parents:QueryList<Parent>;
ngAfterViewInit()
{
// now we have a reference to each ViewChild in the ViewChildren parents:QueryList
this.parents.toArray().forEach((parent:Parent) => { console.log(parent.specUrl); });
}
}
{
"parent" : {"id" : "parent1"},
"child" : {"id" : "child1"},
"subchild" : {"id" : "subchild1"},
"dataUrl" : "./data1.json"
}
{
"parent" : {"id" : "parent2"},
"child" : {"id" : "child2"},
"subchild" : {"id" : "subchild2"},
"dataUrl" : "./data2.json"
}
{
"parent" : {"id" : "parent3"},
"child" : {"id" : "child3"},
"subchild" : {"id" : "subchild3"},
"dataUrl" : "./data3.json"
}
{
"parent" : {"content" : "parent content 1"},
"child" : {"content" : "child content 1"},
"subchild" : {"content" : "subchild content 1"}
}
{
"parent" : {"content" : "parent content 2"},
"child" : {"content" : "child content 2"},
"subchild" : {"content" : "subchild content 2"}
}
{
"parent" : {"content" : "parent content 3"},
"child" : {"content" : "child content 3"},
"subchild" : {"content" : "subchild content 3"}
}
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class DataService
{
constructor(private http:Http) {}
public getSpec(url:string)
{
return this.http
.get(url)
.map(res => res.json())
.catch(this.handleError);
}
public getData(url:string)
{
return this.http
.get(url)
.map(res => res.json())
.catch(this.handleError);
}
private handleError (error: Response)
{
console.log(error);
return Observable.throw(error || 'Server error');
}
}
import {Component, Input, ViewChild} from 'angular2/core';
import {Child} from './child';
import {DataService} from './data.service';
@Component({
selector : 'parent-component',
directives : [Child],
providers : [DataService],
host : {style : 'border: 1px solid green;min-height:20px;display:block;padding:10px;margin:10px;'},
template :
`
<p>{{spec?.parent?.id}} - {{loadEvents}} onLoaded Event(s)</p>
<child-component [spec]="spec" id="{{spec?.child?.id}}" (loaded)="onLoaded($event)"></child-component>
`
})
export class Parent
{
@ViewChild(Child) child:Child;
@Input() specUrl;
private spec:any;
private loadEvents:number = 0;
constructor(private dataService:DataService) {}
ngAfterViewInit()
{
var self:any = this;
this.dataService.getSpec(this.specUrl).subscribe(spec =>
{
self.spec = spec;
// place in a timeout so the change cycle has a chance to
// handle the spec @Input into the Child
window.setTimeout(() => self.child.load(), 0);
});
}
onLoaded(flag)
{
this.loadEvents++;
}
}
import {Component, ViewChild, Input, EventEmitter, Output} from 'angular2/core';
import {SubChild} from './subchild';
@Component({
selector : 'child-component',
directives : [SubChild],
host : {style : 'border: 1px solid red;min-height:20px;display:block;padding:10px;'},
template :
`
<p>{{spec?.child?.id}} - {{loadEvents}} onLoaded Event(s)</p>
<subchild-component [spec]="spec" id="{{spec?.subchild?.id}}" (loaded)="onLoaded($event)"></subchild-component>
`
})
export class Child
{
@ViewChild(SubChild) subchild:SubChild;
@Input() spec:any;
@Output() loaded:EventEmitter<boolean> = new EventEmitter<boolean>();
private loadEvents:number = 0;
onLoaded(flag)
{
this.loadEvents++;
this.loaded.emit(flag);
}
public load()
{
this.subchild.load();
}
}
///<reference path="../../../ts/typings/tsd.d.ts" />
///<reference path="../../../node_modules/angular2/typings/browser.d.ts"/>
import {Component, Input, Output, EventEmitter} from 'angular2/core';
import {DataService} from './data.service';
@Component({
selector : 'subchild-component',
host : {style : 'border: 1px solid blue;min-height:20px;display:block;padding:10px;'},
template :
`
<p>{{spec?.subchild?.id}} - {{data?.subchild?.content}} - </p>
<button id="{{spec?.subchild?.id}}_Button" (click)="onButtonClick($event)" type="button" style="border:1px solid #00733a">Fire Loaded Event</button>
`
})
export class SubChild
{
@Output() loaded:EventEmitter<boolean> = new EventEmitter<boolean>();
@Input() spec:any;
private data:any;
constructor(private dataService:DataService) {}
onButtonClick(event:MouseEvent)
{
this.loaded.emit(true);
}
public load():Promise<any>
{
let self:any = this;
return new Promise(function(resolve, reject)
{
self.dataService.getData(self.spec.dataUrl).subscribe(response =>
{
self.data = response;
resolve(self.data);
self.loaded.emit(true);
});
});
}
}