986 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
		
		
			
		
	
	
			986 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
|  | <html lang="en"><head></head><body><form id="mainForm" method="post" action="http://plnkr.co/edit/?p=preview" target="_self"><input type="hidden" name="files[app/app.component.ts]" value="import { Component, Inject } from '@angular/core'; | ||
|  | 
 | ||
|  | import { APP_CONFIG, AppConfig }    from './app.config'; | ||
|  | import { Logger } from './logger.service'; | ||
|  | import { UserService } from './user.service'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'my-app', | ||
|  |   template:  ` | ||
|  |     <h1>{{title}}</h1> | ||
|  |     <my-car></my-car> | ||
|  |     <my-injectors></my-injectors> | ||
|  |     <my-tests></my-tests> | ||
|  |     <h2>User</h2> | ||
|  |     <p id="user"> | ||
|  |       {{userInfo}} | ||
|  |       <button (click)="nextUser()">Next User</button> | ||
|  |     <p> | ||
|  |     <my-heroes id="authorized" *ngIf="isAuthorized"></my-heroes> | ||
|  |     <my-heroes id="unauthorized" *ngIf="!isAuthorized"></my-heroes> | ||
|  |     <my-providers></my-providers> | ||
|  |   `, | ||
|  |   providers: [Logger] | ||
|  | }) | ||
|  | export class AppComponent { | ||
|  |   title: string; | ||
|  | 
 | ||
|  |   constructor( | ||
|  |     @Inject(APP_CONFIG) config: AppConfig, | ||
|  |     private userService: UserService) { | ||
|  |     this.title = config.title; | ||
|  |   } | ||
|  | 
 | ||
|  |   get isAuthorized() { return this.user.isAuthorized; } | ||
|  |   nextUser()         { this.userService.getNewUser(); } | ||
|  |   get user()         { return this.userService.user; } | ||
|  | 
 | ||
|  |   get userInfo()     { | ||
|  |     return `Current user, ${this.user.name}, is ` + | ||
|  |            `${this.isAuthorized ? '' : 'not'} authorized. `; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/app.config.ts]" value="import { OpaqueToken } from '@angular/core'; | ||
|  | 
 | ||
|  | export let APP_CONFIG = new OpaqueToken('app.config'); | ||
|  | 
 | ||
|  | export interface AppConfig { | ||
|  |   apiEndpoint: string; | ||
|  |   title: string; | ||
|  | } | ||
|  | 
 | ||
|  | export const HERO_DI_CONFIG: AppConfig = { | ||
|  |   apiEndpoint: 'api.heroes.com', | ||
|  |   title: 'Dependency Injection' | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/app.module.ts]" value="import { NgModule } from '@angular/core'; | ||
|  | import { BrowserModule }  from '@angular/platform-browser'; | ||
|  | 
 | ||
|  | import { AppComponent } from './app.component'; | ||
|  | import { CarComponent } from './car/car.component'; | ||
|  | import { HeroesComponent } from './heroes/heroes.component'; | ||
|  | import { HeroListComponent } from './heroes/hero-list.component'; | ||
|  | import { InjectorComponent } from './injector.component'; | ||
|  | import { TestComponent } from './test.component'; | ||
|  | import { APP_CONFIG, HERO_DI_CONFIG }    from './app.config'; | ||
|  | import { UserService } from './user.service'; | ||
|  | import { | ||
|  |   ProvidersComponent, | ||
|  |   Provider1Component, | ||
|  |   Provider3Component, | ||
|  |   Provider4Component, | ||
|  |   Provider5Component, | ||
|  |   Provider6aComponent, | ||
|  |   Provider6bComponent, | ||
|  |   Provider7Component, | ||
|  |   Provider8Component, | ||
|  |   Provider9Component, | ||
|  |   Provider10Component, | ||
|  | } from './providers.component'; | ||
|  | 
 | ||
|  | @NgModule({ | ||
|  |   imports: [ | ||
|  |     BrowserModule | ||
|  |   ], | ||
|  |   declarations: [ | ||
|  |     AppComponent, | ||
|  |     CarComponent, | ||
|  |     HeroesComponent, | ||
|  |     HeroListComponent, | ||
|  |     InjectorComponent, | ||
|  |     TestComponent, | ||
|  |     ProvidersComponent, | ||
|  |     Provider1Component, | ||
|  |     Provider3Component, | ||
|  |     Provider4Component, | ||
|  |     Provider5Component, | ||
|  |     Provider6aComponent, | ||
|  |     Provider6bComponent, | ||
|  |     Provider7Component, | ||
|  |     Provider8Component, | ||
|  |     Provider9Component, | ||
|  |     Provider10Component, | ||
|  |   ], | ||
|  |   providers: [ | ||
|  |     UserService, | ||
|  |     { provide: APP_CONFIG, useValue: HERO_DI_CONFIG } | ||
|  |   ], | ||
|  |   bootstrap: [ AppComponent ] | ||
|  | }) | ||
|  | export class AppModule { } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car-creations.ts]" value="// Examples with car and engine variations | ||
|  | 
 | ||
|  | import { Car, Engine, Tires } from './car'; | ||
|  | 
 | ||
|  | ///////// example 1 //////////// | ||
|  | export function simpleCar() { | ||
|  |   // Simple car with 4 cylinders and Flintstone tires. | ||
|  |   let car = new Car(new Engine(), new Tires()); | ||
|  |   car.description = 'Simple'; | ||
|  |   return car; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | ///////// example 2 //////////// | ||
|  |   class Engine2 { | ||
|  |     constructor(public cylinders: number) { } | ||
|  |   } | ||
|  | export function superCar() { | ||
|  |   // Super car with 12 cylinders and Flintstone tires. | ||
|  |   let bigCylinders = 12; | ||
|  |   let car = new Car(new Engine2(bigCylinders), new Tires()); | ||
|  |   car.description = 'Super'; | ||
|  |   return car; | ||
|  | } | ||
|  | 
 | ||
|  | /////////// example 3 ////////// | ||
|  |   class MockEngine extends Engine { cylinders = 8; } | ||
|  |   class MockTires  extends Tires  { make = 'YokoGoodStone'; } | ||
|  | 
 | ||
|  | export function testCar() { | ||
|  |   // Test car with 8 cylinders and YokoGoodStone tires. | ||
|  |   let car = new Car(new MockEngine(), new MockTires()); | ||
|  |   car.description = 'Test'; | ||
|  |   return car; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car-factory.ts]" value="import { Engine, Tires, Car } from './car'; | ||
|  | 
 | ||
|  | // BAD pattern! | ||
|  | export class CarFactory { | ||
|  |   createCar() { | ||
|  |     let car = new Car(this.createEngine(), this.createTires()); | ||
|  |     car.description = 'Factory'; | ||
|  |     return car; | ||
|  |   } | ||
|  | 
 | ||
|  |   createEngine() { | ||
|  |     return new Engine(); | ||
|  |   } | ||
|  | 
 | ||
|  |   createTires() { | ||
|  |     return new Tires(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car-injector.ts]" value="import { ReflectiveInjector } from '@angular/core'; | ||
|  | 
 | ||
|  | import { Car, Engine, Tires } from './car'; | ||
|  | import { Logger }             from '../logger.service'; | ||
|  | 
 | ||
|  | export function useInjector() { | ||
|  |   let injector: ReflectiveInjector; | ||
|  |   /* | ||
|  |   // Cannot instantiate an ReflectiveInjector like this! | ||
|  |   let injector = new ReflectiveInjector([Car, Engine, Tires]); | ||
|  |   */ | ||
|  |   injector = ReflectiveInjector.resolveAndCreate([Car, Engine, Tires]); | ||
|  |   let car = injector.get(Car); | ||
|  |   car.description = 'Injector'; | ||
|  | 
 | ||
|  |   injector = ReflectiveInjector.resolveAndCreate([Logger]); | ||
|  |   let logger = injector.get(Logger); | ||
|  |   logger.log('Injector car.drive() said: ' + car.drive()); | ||
|  |   return car; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car-no-di.ts]" value="// Car without DI | ||
|  | import { Engine, Tires } from './car'; | ||
|  | 
 | ||
|  | export class Car { | ||
|  | 
 | ||
|  |   public engine: Engine; | ||
|  |   public tires: Tires; | ||
|  |   public description = 'No DI'; | ||
|  | 
 | ||
|  |   constructor() { | ||
|  |     this.engine = new Engine(); | ||
|  |     this.tires = new Tires(); | ||
|  |   } | ||
|  | 
 | ||
|  |   // Method using the engine and tires | ||
|  |   drive() { | ||
|  |     return `${this.description} car with ` + | ||
|  |       `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car.component.ts]" value="import { Component } from '@angular/core'; | ||
|  | 
 | ||
|  | import { Car, Engine, Tires }  from './car'; | ||
|  | import { Car as CarNoDi }      from './car-no-di'; | ||
|  | import { CarFactory }          from './car-factory'; | ||
|  | 
 | ||
|  | import { testCar, | ||
|  |          simpleCar, | ||
|  |          superCar }           from './car-creations'; | ||
|  | 
 | ||
|  | import { useInjector }        from './car-injector'; | ||
|  | 
 | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'my-car', | ||
|  |   template: ` | ||
|  |   <h2>Cars</h2> | ||
|  |   <div id="di">{{car.drive()}}</div> | ||
|  |   <div id="nodi">{{noDiCar.drive()}}</div> | ||
|  |   <div id="injector">{{injectorCar.drive()}}</div> | ||
|  |   <div id="factory">{{factoryCar.drive()}}</div> | ||
|  |   <div id="simple">{{simpleCar.drive()}}</div> | ||
|  |   <div id="super">{{superCar.drive()}}</div> | ||
|  |   <div id="test">{{testCar.drive()}}</div> | ||
|  |   `, | ||
|  |   providers: [Car, Engine, Tires] | ||
|  | }) | ||
|  | export class CarComponent { | ||
|  |   factoryCar  = (new CarFactory).createCar(); | ||
|  |   injectorCar = useInjector(); | ||
|  |   noDiCar     = new CarNoDi; | ||
|  |   simpleCar   = simpleCar(); | ||
|  |   superCar    = superCar(); | ||
|  |   testCar     = testCar(); | ||
|  | 
 | ||
|  |   constructor(public car: Car) {} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/car/car.ts]" value="import { Injectable } from '@angular/core'; | ||
|  | 
 | ||
|  | export class Engine { | ||
|  |   public cylinders = 4; | ||
|  | } | ||
|  | 
 | ||
|  | export class Tires { | ||
|  |   public make  = 'Flintstone'; | ||
|  |   public model = 'Square'; | ||
|  | } | ||
|  | 
 | ||
|  | @Injectable() | ||
|  | export class Car { | ||
|  |   public description = 'DI'; | ||
|  | 
 | ||
|  |   constructor(public engine: Engine, public tires: Tires) { } | ||
|  | 
 | ||
|  |   // Method using the engine and tires | ||
|  |   drive() { | ||
|  |     return `${this.description} car with ` + | ||
|  |       `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/hero-list.component.ts]" value="/* tslint:disable:one-line */ | ||
|  | import { Component }   from '@angular/core'; | ||
|  | 
 | ||
|  | import { Hero }        from './hero'; | ||
|  | import { HeroService } from './hero.service'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'hero-list', | ||
|  |   template: ` | ||
|  |   <div *ngFor="let hero of heroes"> | ||
|  |     {{hero.id}} - {{hero.name}} | ||
|  |     ({{hero.isSecret ? 'secret' : 'public'}}) | ||
|  |   </div> | ||
|  |   `, | ||
|  | }) | ||
|  | export class HeroListComponent { | ||
|  |   heroes: Hero[]; | ||
|  | 
 | ||
|  |   constructor(heroService: HeroService) | ||
|  |   { | ||
|  |     this.heroes = heroService.getHeroes(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/hero.service.provider.ts]" value="/* tslint:disable:one-line */ | ||
|  | import { HeroService } from './hero.service'; | ||
|  | import { Logger }      from '../logger.service'; | ||
|  | import { UserService } from '../user.service'; | ||
|  | 
 | ||
|  | let heroServiceFactory = (logger: Logger, userService: UserService) => { | ||
|  |   return new HeroService(logger, userService.user.isAuthorized); | ||
|  | }; | ||
|  | 
 | ||
|  | export let heroServiceProvider = | ||
|  |   { provide: HeroService, | ||
|  |     useFactory: heroServiceFactory, | ||
|  |     deps: [Logger, UserService] | ||
|  |   }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/hero.service.ts]" value="import { Injectable } from '@angular/core'; | ||
|  | 
 | ||
|  | import { HEROES }     from './mock-heroes'; | ||
|  | import { Logger }     from '../logger.service'; | ||
|  | 
 | ||
|  | @Injectable() | ||
|  | export class HeroService { | ||
|  |   constructor( | ||
|  |     private logger: Logger, | ||
|  |     private isAuthorized: boolean) { } | ||
|  | 
 | ||
|  |   getHeroes() { | ||
|  |     let auth = this.isAuthorized ? 'authorized ' : 'unauthorized'; | ||
|  |     this.logger.log(`Getting heroes for ${auth} user.`); | ||
|  |     return HEROES.filter(hero => this.isAuthorized || !hero.isSecret); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/hero.ts]" value="export class Hero { | ||
|  |   id: number; | ||
|  |   name: string; | ||
|  |   isSecret = false; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/heroes.component.ts]" value="import { Component }          from '@angular/core'; | ||
|  | 
 | ||
|  | import { heroServiceProvider } from './hero.service.provider'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'my-heroes', | ||
|  |   template: ` | ||
|  |   <h2>Heroes</h2> | ||
|  |   <hero-list></hero-list> | ||
|  |   `, | ||
|  |   providers: [heroServiceProvider] | ||
|  | }) | ||
|  | export class HeroesComponent { } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/heroes/mock-heroes.ts]" value="import { Hero } from './hero'; | ||
|  | 
 | ||
|  | export var HEROES: Hero[] = [ | ||
|  |   { id: 11, isSecret: false, name: 'Mr. Nice' }, | ||
|  |   { id: 12, isSecret: false, name: 'Narco' }, | ||
|  |   { id: 13, isSecret: false, name: 'Bombasto' }, | ||
|  |   { id: 14, isSecret: false, name: 'Celeritas' }, | ||
|  |   { id: 15, isSecret: false, name: 'Magneta' }, | ||
|  |   { id: 16, isSecret: false, name: 'RubberMan' }, | ||
|  |   { id: 17, isSecret: false, name: 'Dynama' }, | ||
|  |   { id: 18, isSecret: true,  name: 'Dr IQ' }, | ||
|  |   { id: 19, isSecret: true,  name: 'Magma' }, | ||
|  |   { id: 20, isSecret: true,  name: 'Tornado' } | ||
|  | ]; | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/injector.component.ts]" value="import { Component, Injector }  from '@angular/core'; | ||
|  | 
 | ||
|  | import { Car, Engine, Tires }   from './car/car'; | ||
|  | import { Hero }                 from './heroes/hero'; | ||
|  | import { HeroService }          from './heroes/hero.service'; | ||
|  | import { heroServiceProvider }  from './heroes/hero.service.provider'; | ||
|  | import { Logger }               from './logger.service'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'my-injectors', | ||
|  |   template: ` | ||
|  |   <h2>Other Injections</h2> | ||
|  |   <div id="car">{{car.drive()}}</div> | ||
|  |   <div id="hero">{{hero.name}}</div> | ||
|  |   <div id="rodent">{{rodent}}</div> | ||
|  |   `, | ||
|  |   providers: [Car, Engine, Tires, heroServiceProvider, Logger] | ||
|  | }) | ||
|  | export class InjectorComponent { | ||
|  |   car: Car = this.injector.get(Car); | ||
|  | 
 | ||
|  |   heroService: HeroService = this.injector.get(HeroService); | ||
|  |   hero: Hero = this.heroService.getHeroes()[0]; | ||
|  | 
 | ||
|  |   constructor(private injector: Injector) { } | ||
|  | 
 | ||
|  |   get rodent() { | ||
|  |     let rousDontExist = `R.O.U.S.'s? I don't think they exist!`; | ||
|  |     return this.injector.get(ROUS, rousDontExist); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * R.O.U.S. - Rodents Of Unusual Size | ||
|  |  * // https://www.youtube.com/watch?v=BOv5ZjAOpC8 | ||
|  |  */ | ||
|  | class ROUS { } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/logger.service.ts]" value="import { Injectable } from '@angular/core'; | ||
|  | 
 | ||
|  | @Injectable() | ||
|  | export class Logger { | ||
|  |   logs: string[] = []; // capture logs for testing | ||
|  | 
 | ||
|  |   log(message: string) { | ||
|  |     this.logs.push(message); | ||
|  |     console.log(message); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/providers.component.ts]" value="/* tslint:disable:one-line:check-open-brace*/ | ||
|  | // Examples of provider arrays | ||
|  | import { Component, Inject, Injectable, OnInit } from '@angular/core'; | ||
|  | 
 | ||
|  | import { APP_CONFIG, AppConfig, | ||
|  |          HERO_DI_CONFIG }       from './app.config'; | ||
|  | 
 | ||
|  | import { HeroService }          from './heroes/hero.service'; | ||
|  | import { heroServiceProvider }  from './heroes/hero.service.provider'; | ||
|  | import { Logger }               from './logger.service'; | ||
|  | import { UserService }    from './user.service'; | ||
|  | 
 | ||
|  | let template = '{{log}}'; | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | @Component({ | ||
|  |   selector: 'provider-1', | ||
|  |   template: template, | ||
|  |   providers: [Logger] | ||
|  | }) | ||
|  | export class Provider1Component { | ||
|  |   log: string; | ||
|  |   constructor(logger: Logger) { | ||
|  |     logger.log('Hello from logger provided with Logger class'); | ||
|  |     this.log = logger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | @Component({ | ||
|  |   selector: 'provider-3', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [{ provide: Logger, useClass: Logger }] | ||
|  | }) | ||
|  | export class Provider3Component { | ||
|  |   log: string; | ||
|  |   constructor(logger: Logger) { | ||
|  |     logger.log('Hello from logger provided with useClass:Logger'); | ||
|  |     this.log = logger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | class BetterLogger extends Logger {} | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-4', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [{ provide: Logger, useClass: BetterLogger }] | ||
|  | }) | ||
|  | export class Provider4Component { | ||
|  |   log: string; | ||
|  |   constructor(logger: Logger) { | ||
|  |     logger.log('Hello from logger provided with useClass:BetterLogger'); | ||
|  |     this.log = logger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | @Injectable() | ||
|  | class EvenBetterLogger extends Logger { | ||
|  |   constructor(private userService: UserService) { super(); } | ||
|  | 
 | ||
|  |   log(message: string) { | ||
|  |     let name = this.userService.user.name; | ||
|  |     super.log(`Message to ${name}: ${message}`); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-5', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [ UserService, | ||
|  |       { provide: Logger, useClass: EvenBetterLogger }] | ||
|  | }) | ||
|  | export class Provider5Component { | ||
|  |   log: string; | ||
|  |   constructor(logger: Logger) { | ||
|  |     logger.log('Hello from EvenBetterlogger'); | ||
|  |     this.log = logger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | class NewLogger extends Logger {} | ||
|  | class OldLogger { | ||
|  |   logs: string[] = []; | ||
|  |   log(message: string) { | ||
|  |     throw new Error('Should not call the old logger!'); | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-6a', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [ NewLogger, | ||
|  |       // Not aliased! Creates two instances of `NewLogger` | ||
|  |       { provide: OldLogger, useClass: NewLogger}] | ||
|  | }) | ||
|  | export class Provider6aComponent { | ||
|  |   log: string; | ||
|  |   constructor(newLogger: NewLogger, oldLogger: OldLogger) { | ||
|  |     if (newLogger === oldLogger){ | ||
|  |       throw new Error('expected the two loggers to be different instances'); | ||
|  |     } | ||
|  |     oldLogger.log('Hello OldLogger (but we want NewLogger)'); | ||
|  |     // The newLogger wasn't called so no logs[] | ||
|  |     // display the logs of the oldLogger. | ||
|  |     this.log = newLogger.logs[0] || oldLogger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-6b', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [ NewLogger, | ||
|  |       // Alias OldLogger w/ reference to NewLogger | ||
|  |       { provide: OldLogger, useExisting: NewLogger}] | ||
|  | }) | ||
|  | export class Provider6bComponent { | ||
|  |   log: string; | ||
|  |   constructor(newLogger: NewLogger, oldLogger: OldLogger) { | ||
|  |     if (newLogger !== oldLogger){ | ||
|  |       throw new Error('expected the two loggers to be the same instance'); | ||
|  |     } | ||
|  |     oldLogger.log('Hello from NewLogger (via aliased OldLogger)'); | ||
|  |     this.log = newLogger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////////////// | ||
|  | // An object in the shape of the logger service | ||
|  | let silentLogger = { | ||
|  |   logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'], | ||
|  |   log: () => {} | ||
|  | }; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-7', | ||
|  |   template: template, | ||
|  |   providers: | ||
|  |     [{ provide: Logger, useValue: silentLogger }] | ||
|  | }) | ||
|  | export class Provider7Component { | ||
|  |   log: string; | ||
|  |   constructor(logger: Logger) { | ||
|  |     logger.log('Hello from logger provided with useValue'); | ||
|  |     this.log = logger.logs[0]; | ||
|  |   } | ||
|  | } | ||
|  | ///////////////// | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-8', | ||
|  |   template: template, | ||
|  |   providers: [heroServiceProvider, Logger, UserService] | ||
|  | }) | ||
|  | export class Provider8Component { | ||
|  |   // must be true else this component would have blown up at runtime | ||
|  |   log = 'Hero service injected successfully via heroServiceProvider'; | ||
|  | 
 | ||
|  |   constructor(heroService: HeroService) { } | ||
|  | } | ||
|  | 
 | ||
|  | ///////////////// | ||
|  | @Component({ | ||
|  |   selector: 'provider-9', | ||
|  |   template: template, | ||
|  |   /* | ||
|  |    // FAIL! Can't use interface as provider token | ||
|  |    [{ provide: AppConfig, useValue: HERO_DI_CONFIG })] | ||
|  |    */ | ||
|  |   providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }] | ||
|  | }) | ||
|  | export class Provider9Component implements OnInit { | ||
|  |   log: string; | ||
|  |   /* | ||
|  |    // FAIL! Can't inject using the interface as the parameter type | ||
|  |    constructor(private config: AppConfig){ } | ||
|  |    */ | ||
|  |   constructor(@Inject(APP_CONFIG) private config: AppConfig) { } | ||
|  | 
 | ||
|  |   ngOnInit() { | ||
|  |      this.log = 'APP_CONFIG Application title is ' + this.config.title; | ||
|  |   } | ||
|  | } | ||
|  | ////////////////////////////////////////// | ||
|  | // Sample providers 1 to 7 illustrate a required logger dependency. | ||
|  | // Optional logger, can be null | ||
|  | import { Optional } from '@angular/core'; | ||
|  | 
 | ||
|  | let some_message = 'Hello from the injected logger'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'provider-10', | ||
|  |   template: template, | ||
|  |   providers: [{ provide: Logger, useValue: null }] | ||
|  | }) | ||
|  | export class Provider10Component implements OnInit { | ||
|  |   log: string; | ||
|  |   constructor(@Optional() private logger: Logger) { | ||
|  |     if (this.logger) { | ||
|  |       this.logger.log(some_message); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   ngOnInit() { | ||
|  |     this.log = this.logger ? this.logger.logs[0] : 'Optional logger was not available'; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | ///////////////// | ||
|  | @Component({ | ||
|  |   selector: 'my-providers', | ||
|  |   template: ` | ||
|  |   <h2>Provider variations</h2> | ||
|  |   <div id="p1"><provider-1></provider-1></div> | ||
|  |   <div id="p3"><provider-3></provider-3></div> | ||
|  |   <div id="p4"><provider-4></provider-4></div> | ||
|  |   <div id="p5"><provider-5></provider-5></div> | ||
|  |   <div id="p6a"><provider-6a></provider-6a></div> | ||
|  |   <div id="p6b"><provider-6b></provider-6b></div> | ||
|  |   <div id="p7"><provider-7></provider-7></div> | ||
|  |   <div id="p8"><provider-8></provider-8></div> | ||
|  |   <div id="p9"><provider-9></provider-9></div> | ||
|  |   <div id="p10"><provider-10></provider-10></div> | ||
|  |   ` | ||
|  | }) | ||
|  | export class ProvidersComponent { } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/test.component.ts]" value="/* tslint:disable */ | ||
|  | // Simulate a simple test | ||
|  | // Reader should look to the testing chapter for the real thing | ||
|  | 
 | ||
|  | import { Component }           from '@angular/core'; | ||
|  | 
 | ||
|  | import { HeroService }         from './heroes/hero.service'; | ||
|  | import { HeroListComponent }   from './heroes/hero-list.component'; | ||
|  | 
 | ||
|  | @Component({ | ||
|  |   selector: 'my-tests', | ||
|  |   template: ` | ||
|  |     <h2>Tests</h2> | ||
|  |     <p id="tests">Tests {{results.pass}}: {{results.message}}</p> | ||
|  |   ` | ||
|  | }) | ||
|  | export class TestComponent { | ||
|  |   results = runTests(); | ||
|  | } | ||
|  | 
 | ||
|  | ///////////////////////////////////// | ||
|  | function runTests() { | ||
|  | 
 | ||
|  |   let expectedHeroes = [{name: 'A'}, {name: 'B'}] | ||
|  |   let mockService = <HeroService> {getHeroes: () => expectedHeroes } | ||
|  | 
 | ||
|  |   it('should have heroes when HeroListComponent created', () => { | ||
|  |     let hlc = new HeroListComponent(mockService); | ||
|  |     expect(hlc.heroes.length).toEqual(expectedHeroes.length); | ||
|  |   }); | ||
|  | 
 | ||
|  |   return testResults; | ||
|  | } | ||
|  | 
 | ||
|  | ////////////////////////////////// | ||
|  | // Fake Jasmine infrastructure | ||
|  | var testName: string; | ||
|  | var testResults: {pass: string; message: string}; | ||
|  | 
 | ||
|  | function expect(actual: any) { | ||
|  |   return { | ||
|  |     toEqual: function(expected: any){ | ||
|  |       testResults = actual === expected ? | ||
|  |         {pass: 'passed', message: testName} : | ||
|  |         {pass: 'failed', message: `${testName}; expected ${actual} to equal ${expected}.`}; | ||
|  |     } | ||
|  |   }; | ||
|  | } | ||
|  | 
 | ||
|  | function it(label: string, test: () => void) { | ||
|  |   testName = label; | ||
|  |   test(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[app/user.service.ts]" value="import { Injectable } from '@angular/core'; | ||
|  | 
 | ||
|  | export class User { | ||
|  |   constructor( | ||
|  |     public name: string, | ||
|  |     public isAuthorized = false) { } | ||
|  | } | ||
|  | 
 | ||
|  | // Todo: get the user; don't 'new' it. | ||
|  | let alice = new User('Alice', true); | ||
|  | let bob = new User('Bob', false); | ||
|  | 
 | ||
|  | @Injectable() | ||
|  | export class UserService { | ||
|  |   user = bob;  // initial user is Bob | ||
|  | 
 | ||
|  |   // swap users | ||
|  |   getNewUser() { | ||
|  |     return this.user = this.user === bob ? alice : bob; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[main.ts]" value="import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; | ||
|  | import { AppModule }              from './app/app.module'; | ||
|  | 
 | ||
|  | platformBrowserDynamic().bootstrapModule(AppModule); | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[styles.css]" value="/* Master Styles */ | ||
|  | h1 { | ||
|  |   color: #369; | ||
|  |   font-family: Arial, Helvetica, sans-serif; | ||
|  |   font-size: 250%; | ||
|  | } | ||
|  | h2, h3 { | ||
|  |   color: #444; | ||
|  |   font-family: Arial, Helvetica, sans-serif; | ||
|  |   font-weight: lighter; | ||
|  | } | ||
|  | body { | ||
|  |   margin: 2em; | ||
|  | } | ||
|  | body, input[text], button { | ||
|  |   color: #888; | ||
|  |   font-family: Cambria, Georgia; | ||
|  | } | ||
|  | a { | ||
|  |   cursor: pointer; | ||
|  |   cursor: hand; | ||
|  | } | ||
|  | button { | ||
|  |   font-family: Arial; | ||
|  |   background-color: #eee; | ||
|  |   border: none; | ||
|  |   padding: 5px 10px; | ||
|  |   border-radius: 4px; | ||
|  |   cursor: pointer; | ||
|  |   cursor: hand; | ||
|  | } | ||
|  | button:hover { | ||
|  |   background-color: #cfd8dc; | ||
|  | } | ||
|  | button:disabled { | ||
|  |   background-color: #eee; | ||
|  |   color: #aaa; | ||
|  |   cursor: auto; | ||
|  | } | ||
|  | 
 | ||
|  | /* Navigation link styles */ | ||
|  | nav a { | ||
|  |   padding: 5px 10px; | ||
|  |   text-decoration: none; | ||
|  |   margin-right: 10px; | ||
|  |   margin-top: 10px; | ||
|  |   display: inline-block; | ||
|  |   background-color: #eee; | ||
|  |   border-radius: 4px; | ||
|  | } | ||
|  | nav a:visited, a:link { | ||
|  |   color: #607D8B; | ||
|  | } | ||
|  | nav a:hover { | ||
|  |   color: #039be5; | ||
|  |   background-color: #CFD8DC; | ||
|  | } | ||
|  | nav a.active { | ||
|  |   color: #039be5; | ||
|  | } | ||
|  | 
 | ||
|  | /* items class */ | ||
|  | .items { | ||
|  |   margin: 0 0 2em 0; | ||
|  |   list-style-type: none; | ||
|  |   padding: 0; | ||
|  |   width: 24em; | ||
|  | } | ||
|  | .items li { | ||
|  |   cursor: pointer; | ||
|  |   position: relative; | ||
|  |   left: 0; | ||
|  |   background-color: #EEE; | ||
|  |   margin: .5em; | ||
|  |   padding: .3em 0; | ||
|  |   height: 1.6em; | ||
|  |   border-radius: 4px; | ||
|  | } | ||
|  | .items li:hover { | ||
|  |   color: #607D8B; | ||
|  |   background-color: #DDD; | ||
|  |   left: .1em; | ||
|  | } | ||
|  | .items li.selected { | ||
|  |   background-color: #CFD8DC; | ||
|  |   color: white; | ||
|  | } | ||
|  | .items li.selected:hover { | ||
|  |   background-color: #BBD8DC; | ||
|  | } | ||
|  | .items .text { | ||
|  |   position: relative; | ||
|  |   top: -3px; | ||
|  | } | ||
|  | .items .badge { | ||
|  |   display: inline-block; | ||
|  |   font-size: small; | ||
|  |   color: white; | ||
|  |   padding: 0.8em 0.7em 0 0.7em; | ||
|  |   background-color: #607D8B; | ||
|  |   line-height: 1em; | ||
|  |   position: relative; | ||
|  |   left: -1px; | ||
|  |   top: -4px; | ||
|  |   height: 1.8em; | ||
|  |   margin-right: .8em; | ||
|  |   border-radius: 4px 0 0 4px; | ||
|  | } | ||
|  | /* everywhere else */ | ||
|  | * { | ||
|  |   font-family: Arial, Helvetica, sans-serif; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | */"><input type="hidden" name="files[index.html]" value="<!DOCTYPE html> | ||
|  | <html> | ||
|  |   <head> | ||
|  |     <title>Dependency Injection</title> | ||
|  |     <script>document.write('<base href="' + document.location + '" />');</script> | ||
|  |     <meta charset="UTF-8"> | ||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||
|  |     <link rel="stylesheet" href="styles.css"> | ||
|  | 
 | ||
|  |     <!-- Polyfills --> | ||
|  |     <script src="https://unpkg.com/core-js/client/shim.min.js"></script> | ||
|  | 
 | ||
|  |     <script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script> | ||
|  |     <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script> | ||
|  | 
 | ||
|  |     <script src="https://cdn.rawgit.com/angular/angular.io/b3c65a9/public/docs/_examples/_boilerplate/systemjs.config.web.js"></script> | ||
|  |     <script> | ||
|  |       System.import('main.js').catch(function(err){ console.error(err); }); | ||
|  |     </script> | ||
|  |   </head> | ||
|  | 
 | ||
|  |   <body> | ||
|  |     <my-app>Loading my-app ...</my-app> | ||
|  |   </body> | ||
|  | 
 | ||
|  | </html> | ||
|  | 
 | ||
|  | 
 | ||
|  | <!-- 
 | ||
|  | Copyright 2016 Google Inc. All Rights Reserved. | ||
|  | Use of this source code is governed by an MIT-style license that | ||
|  | can be found in the LICENSE file at http://angular.io/license | ||
|  | -->"><input type="hidden" name="tags[0]" value="angular"><input type="hidden" name="tags[1]" value="example"><input type="hidden" name="tags[2]" value="dependency"><input type="hidden" name="tags[3]" value="di"><input type="hidden" name="private" value="true"><input type="hidden" name="description" value="Angular Example - Dependency Injection"></form><script>document.getElementById("mainForm").submit();</script></body></html> |