231 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /* tslint:disable:no-unused-variable component-selector-name one-line check-open-brace */
 | |
| /* tslint:disable:*/
 | |
| // #docplaster
 | |
| // #docregion
 | |
| import { Component, forwardRef, Optional, provide, SkipSelf } from '@angular/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) => {
 | |
|     return { 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) => {
 | |
|     return { 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 { }
 |