<!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);
            });
        });
    }
}