228 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			228 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | /* tslint:disable:no-unused-variable */ | ||
|  | /* tslint:disable:one-line:check-open-brace*/ | ||
|  | // #docplaster
 | ||
|  | // #docregion
 | ||
|  | import { Component, forwardRef, Optional, provide, SkipSelf } from 'angular2/core'; | ||
|  | 
 | ||
|  | // A component base class (see AlexComponent)
 | ||
|  | export abstract class Base { name = 'Count Basie'; } | ||
|  | 
 | ||
|  | // Marker class, used as an interface
 | ||
|  | // #docregion parent
 | ||
|  | export abstract class Parent { name: string; } | ||
|  | // #enddocregion parent
 | ||
|  | 
 | ||
|  | const DifferentParent = Parent; | ||
|  | 
 | ||
|  | // #docregion provide-parent, provide-the-parent
 | ||
|  | // Helper method to provide the current component instance in the name of a `parentType`.
 | ||
|  | // #enddocregion provide-the-parent
 | ||
|  | // The `parentType` defaults to `Parent` when omitting the second parameter.
 | ||
|  | // #docregion provide-the-parent
 | ||
|  | const provideParent = | ||
|  | // #enddocregion provide-parent, provide-the-parent
 | ||
|  | // #docregion provide-parent
 | ||
|  |   (component: any, parentType?: any) => | ||
|  |     provide(parentType || Parent, { useExisting: forwardRef(() => component) }); | ||
|  | // #enddocregion provide-parent
 | ||
|  | 
 | ||
|  | // Simpler syntax version that always provides the component in the name of `Parent`.
 | ||
|  | const provideTheParent = | ||
|  | // #docregion provide-the-parent
 | ||
|  |   (component: any) => provide(Parent, { useExisting: forwardRef(() => component) }); | ||
|  | // #enddocregion provide-the-parent
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ///////// C - Child //////////
 | ||
|  | // #docregion carol
 | ||
|  | const templateC = `
 | ||
|  |   <div class="c"> | ||
|  |     <h3>{{name}}</h3> | ||
|  |     <p>My parent is {{parent?.name}}</p> | ||
|  |   </div>`;
 | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'carol', | ||
|  |   template: templateC | ||
|  | }) | ||
|  | // #docregion carol-class
 | ||
|  | export class CarolComponent { | ||
|  |   name= 'Carol'; | ||
|  |   // #docregion carol-ctor
 | ||
|  |   constructor( @Optional() public parent: Parent ) { } | ||
|  |   // #enddocregion carol-ctor
 | ||
|  | } | ||
|  | // #enddocregion carol-class
 | ||
|  | // #enddocregion carol
 | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'chris', | ||
|  |   template: templateC | ||
|  | }) | ||
|  | export class ChrisComponent { | ||
|  |   name= 'Chris'; | ||
|  |   constructor( @Optional() public parent: Parent ) { } | ||
|  | } | ||
|  | 
 | ||
|  | //////  Craig ///////////
 | ||
|  | /** | ||
|  |  * Show we cannot inject a parent by its base class. | ||
|  |  */ | ||
|  | // #docregion craig
 | ||
|  | @Component({ | ||
|  |   selector: 'craig', | ||
|  |   template: `
 | ||
|  |   <div class="c"> | ||
|  |     <h3>Craig</h3> | ||
|  |     {{alex ? 'Found' : 'Did not find'}} Alex via the base class. | ||
|  |   </div>`
 | ||
|  | }) | ||
|  | export class CraigComponent { | ||
|  |   constructor( @Optional() public alex: Base ) { } | ||
|  | } | ||
|  | // #enddocregion craig
 | ||
|  | 
 | ||
|  | // #docregion C_DIRECTIVES
 | ||
|  | const C_DIRECTIVES = [ | ||
|  |   CarolComponent, ChrisComponent, CraigComponent, | ||
|  |   forwardRef(() => CathyComponent) | ||
|  | ]; | ||
|  | // #enddocregion C_DIRECTIVES
 | ||
|  | 
 | ||
|  | //////// B - Parent /////////
 | ||
|  | // #docregion barry
 | ||
|  | const templateB = `
 | ||
|  |   <div class="b"> | ||
|  |     <div> | ||
|  |       <h3>{{name}}</h3> | ||
|  |       <p>My parent is {{parent?.name}}</p> | ||
|  |     </div> | ||
|  |     <carol></carol> | ||
|  |     <chris></chris> | ||
|  |   </div>`;
 | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector:   'barry', | ||
|  |   template:   templateB, | ||
|  |   directives: C_DIRECTIVES, | ||
|  |   providers:  [ provide(Parent, { useExisting: forwardRef(() => BarryComponent) }) ] | ||
|  | }) | ||
|  | export class BarryComponent implements Parent { | ||
|  |   name = 'Barry'; | ||
|  | // #docregion barry-ctor
 | ||
|  |   constructor( @SkipSelf() @Optional() public parent: Parent ) { } | ||
|  | // #enddocregion barry-ctor
 | ||
|  | } | ||
|  | // #enddocregion barry
 | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector:   'bob', | ||
|  |   template:   templateB, | ||
|  |   directives: C_DIRECTIVES, | ||
|  |   providers:  [ provideParent(BobComponent) ] | ||
|  | }) | ||
|  | export class BobComponent implements Parent { | ||
|  |   name= 'Bob'; | ||
|  |   constructor( @SkipSelf() @Optional() public parent: Parent ) { } | ||
|  | } | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector:   'beth', | ||
|  |   template:   templateB, | ||
|  |   directives: C_DIRECTIVES, | ||
|  | // #docregion beth-providers
 | ||
|  |   providers:  [ provideParent(BethComponent, DifferentParent) ] | ||
|  | // #enddocregion beth-providers
 | ||
|  | }) | ||
|  | export class BethComponent implements Parent { | ||
|  |   name= 'Beth'; | ||
|  |   constructor( @SkipSelf() @Optional() public parent: Parent ) { } | ||
|  | } | ||
|  | 
 | ||
|  | const B_DIRECTIVES = [ BarryComponent, BethComponent, BobComponent ]; | ||
|  | 
 | ||
|  | ///////// A - Grandparent //////
 | ||
|  | 
 | ||
|  | // #docregion alex, alex-1
 | ||
|  | @Component({ | ||
|  |   selector: 'alex', | ||
|  |   template: `
 | ||
|  |     <div class="a"> | ||
|  |       <h3>{{name}}</h3> | ||
|  |       <cathy></cathy> | ||
|  |       <craig></craig> | ||
|  |       <carol></carol> | ||
|  |     </div>`,
 | ||
|  | // #enddocregion alex-1
 | ||
|  | // #docregion alex-providers
 | ||
|  |   providers: [ provide(Parent, { useExisting: forwardRef(() => AlexComponent) }) ], | ||
|  | // #enddocregion alex-providers
 | ||
|  | // #docregion alex-1
 | ||
|  |   directives: C_DIRECTIVES | ||
|  | }) | ||
|  | // #enddocregion alex-1
 | ||
|  | // Todo: Add `... implements Parent` to class signature
 | ||
|  | // #docregion alex-1
 | ||
|  | // #docregion alex-class-signature
 | ||
|  | export class AlexComponent extends Base | ||
|  | // #enddocregion alex-class-signature
 | ||
|  | { | ||
|  |   name= 'Alex'; | ||
|  | } | ||
|  | // #enddocregion alex, alex-1
 | ||
|  | 
 | ||
|  | /////
 | ||
|  | 
 | ||
|  | // #docregion alice
 | ||
|  | @Component({ | ||
|  |   selector: 'alice', | ||
|  |   template: `
 | ||
|  |     <div class="a"> | ||
|  |       <h3>{{name}}</h3> | ||
|  |       <barry></barry> | ||
|  |       <beth></beth> | ||
|  |       <bob></bob> | ||
|  |       <carol></carol> | ||
|  |     </div> `,
 | ||
|  |   directives: [ B_DIRECTIVES, C_DIRECTIVES ], | ||
|  | // #docregion alice-providers
 | ||
|  |   providers:  [ provideParent(AliceComponent) ] | ||
|  | // #enddocregion alice-providers
 | ||
|  | }) | ||
|  | // #docregion alice-class-signature
 | ||
|  | export class AliceComponent implements Parent | ||
|  | // #enddocregion alice-class-signature
 | ||
|  | { | ||
|  |   name= 'Alice'; | ||
|  | } | ||
|  | // #enddocregion alice
 | ||
|  | 
 | ||
|  | //////  Cathy ///////////
 | ||
|  | /** | ||
|  |  * Show we can inject a parent by component type | ||
|  |  */ | ||
|  | // #docregion cathy
 | ||
|  | @Component({ | ||
|  |   selector: 'cathy', | ||
|  |   template: `
 | ||
|  |   <div class="c"> | ||
|  |     <h3>Cathy</h3> | ||
|  |     {{alex ? 'Found' : 'Did not find'}} Alex via the component class.<br> | ||
|  |   </div>`
 | ||
|  | }) | ||
|  | export class CathyComponent { | ||
|  |   constructor( @Optional() public alex: AlexComponent ) { } | ||
|  | } | ||
|  | // #enddocregion cathy
 | ||
|  | 
 | ||
|  | ///////// ParentFinder //////
 | ||
|  | @Component({ | ||
|  |   selector: 'parent-finder', | ||
|  |   template: `
 | ||
|  |     <h2>Parent Finder</h2> | ||
|  |     <alex></alex> | ||
|  |     <alice></alice>`,
 | ||
|  |   directives: [ AlexComponent, AliceComponent ] | ||
|  | }) | ||
|  | export class ParentFinderComponent { } |