docs(dependency-injection): added DI examples; update/expand text

closes #748
This commit is contained in:
Pascal Precht 2016-01-11 13:49:12 +01:00 committed by Ward Bell
parent 77db0755c8
commit 76a8d022a7
44 changed files with 2207 additions and 406 deletions

View File

@ -0,0 +1,213 @@
describe('Dependency Injection Tests', function () {
var expectedMsg;
beforeAll(function () {
browser.get('');
});
describe('Cars:', function() {
it('DI car displays as expected', function () {
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#di')).getText()).toEqual(expectedMsg);
});
it('No DI car displays as expected', function () {
expectedMsg = 'No DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#nodi')).getText()).toEqual(expectedMsg);
});
it('Injector car displays as expected', function () {
expectedMsg = 'Injector car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#injector')).getText()).toEqual(expectedMsg);
});
it('Factory car displays as expected', function () {
expectedMsg = 'Factory car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#factory')).getText()).toEqual(expectedMsg);
});
it('Simple car displays as expected', function () {
expectedMsg = 'Simple car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#simple')).getText()).toEqual(expectedMsg);
});
it('Super car displays as expected', function () {
expectedMsg = 'Super car with 12 cylinders and Flintstone tires.';
expect(element(by.css('#super')).getText()).toEqual(expectedMsg);
});
it('Test car displays as expected', function () {
expectedMsg = 'Test car with 8 cylinders and YokoGoodStone tires.';
expect(element(by.css('#test')).getText()).toEqual(expectedMsg);
});
});
describe('Other Injections:', function() {
it('DI car displays as expected', function () {
expectedMsg = 'DI car with 4 cylinders and Flintstone tires.';
expect(element(by.css('#car')).getText()).toEqual(expectedMsg);
});
it('Hero displays as expected', function () {
expectedMsg = 'Mr. Nice';
expect(element(by.css('#hero')).getText()).toEqual(expectedMsg);
});
it('Optional injection displays as expected', function () {
expectedMsg = 'R.O.U.S.\'s? I don\'t think they exist!';
expect(element(by.css('#rodent')).getText()).toEqual(expectedMsg);
});
});
describe('Tests:', function() {
it('Tests display as expected', function () {
expectedMsg = /Tests passed/;
expect(element(by.css('#tests')).getText()).toMatch(expectedMsg);
});
});
describe('Provider variations:', function() {
it('P1 (class) displays as expected', function () {
expectedMsg = 'Hello from logger provided with Logger class';
expect(element(by.css('#p1')).getText()).toEqual(expectedMsg);
});
it('P2 (Provider) displays as expected', function () {
expectedMsg = 'Hello from logger provided with Provider class and useClass';
expect(element(by.css('#p2')).getText()).toEqual(expectedMsg);
});
it('P3 (provide) displays as expected', function () {
expectedMsg = 'Hello from logger provided with useClass';
expect(element(by.css('#p3')).getText()).toEqual(expectedMsg);
});
it('P4 (useClass:BetterLogger) displays as expected', function () {
expectedMsg = 'Hello from logger provided with useClass:BetterLogger';
expect(element(by.css('#p4')).getText()).toEqual(expectedMsg);
});
it('P5 (useClass:EvenBetterLogger - dependency) displays as expected', function () {
expectedMsg = 'Message to Bob: Hello from EvenBetterlogger.';
expect(element(by.css('#p5')).getText()).toEqual(expectedMsg);
});
it('P6a (no alias) displays as expected', function () {
expectedMsg = 'Hello OldLogger (but we want NewLogger)';
expect(element(by.css('#p6a')).getText()).toEqual(expectedMsg);
});
it('P6b (alias) displays as expected', function () {
expectedMsg = 'Hello from NewLogger (via aliased OldLogger)';
expect(element(by.css('#p6b')).getText()).toEqual(expectedMsg);
});
it('P7 (useValue) displays as expected', function () {
expectedMsg = 'Silent logger says "Shhhhh!". Provided via "useValue"';
expect(element(by.css('#p7')).getText()).toEqual(expectedMsg);
});
it('P8 (useFactory) displays as expected', function () {
expectedMsg = 'Hero service injected successfully';
expect(element(by.css('#p8')).getText()).toEqual(expectedMsg);
});
it('P9a (string token) displays as expected', function () {
expectedMsg = '"app.config" Application title is Dependency Injection';
expect(element(by.css('#p9a')).getText()).toEqual(expectedMsg);
});
it('P9b (OpaqueToken) displays as expected', function () {
expectedMsg = 'APP_CONFIG Application title is Dependency Injection';
expect(element(by.css('#p9b')).getText()).toEqual(expectedMsg);
});
it('P10a (required dependency) displays as expected', function () {
expectedMsg = 'Hello from the required logger.';
expect(element(by.css('#p10a')).getText()).toEqual(expectedMsg);
});
it('P10b (optional dependency) displays as expected', function () {
expectedMsg = 'Optional logger was not available.';
expect(element(by.css('#p10b')).getText()).toEqual(expectedMsg);
})
});
describe('User/Heroes:', function() {
it('User is Bob - unauthorized', function () {
expectedMsg = /Bob, is not authorized/;
expect(element(by.css('#user')).getText()).toMatch(expectedMsg);
});
it('should have button', function () {
expect(element.all(by.cssContainingText('button','Next User'))
.get(0).isDisplayed()).toBe(true, "'Next User' button should be displayed");
});
it('unauthorized user should have multiple unauthorized heroes', function () {
var heroes = element.all(by.css('#unauthorized hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('unauthorized user should have no secret heroes', function () {
var heroes = element.all(by.css('#unauthorized hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
heroes.filter(function(elem, index){
return elem.getText().then(function(text) {
return /secret/.test(text);
});
}).then(function(filteredElements) {
//console.log("******Secret heroes count: "+filteredElements.length);
expect(filteredElements.length).toEqual(0);
});
});
it('unauthorized user should have no authorized heros listed', function () {
expect(element.all(by.css('#authorized hero-list div')).count()).toEqual(0);
});
describe('after button click', function() {
beforeAll(function (done) {
var buttonEle = element.all(by.cssContainingText('button','Next User')).get(0);
buttonEle.click().then(done,done);
});
it('User is Alice - authorized', function () {
expectedMsg = /Alice, is authorized/;
expect(element(by.css('#user')).getText()).toMatch(expectedMsg);
});
it('authorized user should have multiple authorized heroes ', function () {
var heroes = element.all(by.css('#authorized hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
});
it('authorized user should have secret heroes', function () {
var heroes = element.all(by.css('#authorized hero-list div'));
expect(heroes.count()).toBeGreaterThan(0);
heroes.filter(function(elem, index){
return elem.getText().then(function(text) {
return /secret/.test(text);
});
}).then(function(filteredElements) {
//console.log("******Secret heroes count: "+filteredElements.length);
expect(filteredElements.length).toBeGreaterThan(0);
});
});
it('authorized user should have no unauthorized heros listed', function () {
expect(element.all(by.css('#unauthorized hero-list div')).count()).toEqual(0);
});
});
});
});

View File

@ -0,0 +1 @@
**/*.js

View File

@ -0,0 +1,31 @@
// Early versions
// #docregion
import {Component} from 'angular2/core';
import {CarComponent} from './car/car.component';
import {HeroesComponent} from './heroes/heroes.component.1';
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<my-car></my-car>
<my-heroes></my-heroes>
`,
directives:[CarComponent, HeroesComponent]
})
export class AppComponent {
title = 'Dependency Injection';
}
// #enddocregion
/*
//#docregion ctor-di-fail
// FAIL! Injectable `config` is not a class!
constructor(heroService: HeroService, config: config) {
this.title = config.title;
}
//#enddocregion ctor-di-fail
*/

View File

@ -0,0 +1,39 @@
// #docregion
// #docregion imports
import {Component} from 'angular2/core';
import {CarComponent} from './car/car.component';
import {HeroesComponent} from './heroes/heroes.component.1';
import {provide, Inject} from 'angular2/core';
import {Config, CONFIG} from './app.config';
import {Logger} from './logger.service';
// #enddocregion imports
@Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<my-car></my-car>
<my-heroes></my-heroes>
`,
directives:[CarComponent, HeroesComponent],
// #docregion providers
providers: [
Logger,
// #docregion provider-config
provide('app.config', {useValue: CONFIG})
// #enddocregion provider-config
]
// #docregion providers
})
export class AppComponent {
title:string;
// #docregion ctor
constructor(@Inject('app.config') config:Config) {
this.title = config.title;
}
// #docregion ctor
}
// #enddocregion

View File

@ -0,0 +1,65 @@
// #docplaster
// #docregion
// #docregion imports
import {Component, Inject, provide} from 'angular2/core';
import {CarComponent} from './car/car.component';
import {HeroesComponent} from './heroes/heroes.component';
import {APP_CONFIG,
Config, CONFIG} from './app.config';
import {Logger} from './logger.service';
import {User, UserService} from './user.service';
// #enddocregion imports
import {InjectorComponent} from './injector.component';
import {TestComponent} from './test.component';
import {ProvidersComponent} from './providers.component';
@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>
`,
directives:[CarComponent, HeroesComponent,
InjectorComponent, TestComponent, ProvidersComponent],
// #docregion providers
providers: [
Logger,
UserService,
provide(APP_CONFIG, {useValue: CONFIG})
]
// #enddocregion providers
})
export class AppComponent {
title:string;
//#docregion ctor
constructor(
@Inject(APP_CONFIG) config:Config,
private _userService: UserService) {
this.title = config.title;
}
// #enddocregion ctor
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. `;
}
}
// #enddocregion

View File

@ -0,0 +1,18 @@
//#docregion
// #docregion token
import {OpaqueToken} from 'angular2/core';
export let APP_CONFIG = new OpaqueToken('app.config');
// #enddocregion token
//#docregion config
export interface Config {
apiEndpoint: string,
title: string
}
export const CONFIG:Config = {
apiEndpoint: 'api.heroes.com',
title: 'Dependency Injection'
};
//#enddocregion config

View File

@ -0,0 +1,46 @@
// Examples with car and engine variations
// #docplaster
import {Car, Engine, Tires} from './car';
///////// example 1 ////////////
export function simpleCar() {
//#docregion car-ctor-instantiation
// Simple car with 4 cylinders and Flintstone tires.
var car = new Car(new Engine(), new Tires());
//#enddocregion car-ctor-instantiation
car.description = 'Simple';
return car;
}
///////// example 2 ////////////
//#docregion car-ctor-instantiation-with-param
class Engine2 {
constructor(public cylinders: number) { }
}
//#enddocregion car-ctor-instantiation-with-param
export function superCar() {
//#docregion car-ctor-instantiation-with-param
// Super car with 12 cylinders and Flintstone tires.
var bigCylinders = 12;
var car = new Car(new Engine2(bigCylinders), new Tires());
//#enddocregion car-ctor-instantiation-with-param
car.description = 'Super';
return car;
}
/////////// example 3 //////////
//#docregion car-ctor-instantiation-with-mocks
class MockEngine extends Engine { cylinders = 8; }
class MockTires extends Tires { make = "YokoGoodStone"; }
//#enddocregion car-ctor-instantiation-with-mocks
export function testCar() {
//#docregion car-ctor-instantiation-with-mocks
// Test car with 8 cylinders and YokoGoodStone tires.
var car = new Car(new MockEngine(), new MockTires());
//#enddocregion car-ctor-instantiation-with-mocks
car.description = 'Test';
return car;
}

View File

@ -0,0 +1,19 @@
// #docregion
import {Engine, Tires, Car} from './car';
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();
}
}

View File

@ -0,0 +1,37 @@
// #docplaster
//#docregion
import { Injector } from 'angular2/core';
import {Car, Engine, Tires} from './car';
import {Logger} from '../logger.service';
//#docregion injector
export function useInjector() {
var injector:Injector;
//#enddocregion injector
/*
//#docregion injector-no-new
// Cannot 'new' an Injector like this!
var injector = new Injector([Car, Engine, Tires, Logger]);
//#enddocregion injector-no-new
*/
//#docregion injector
//#docregion injector-create-and-call
injector = Injector.resolveAndCreate([Car, Engine, Tires, Logger]);
//#docregion injector-call
var car = injector.get(Car);
//#enddocregion injector-call
//#enddocregion injector-create-and-call
car.description = 'Injector';
var logger = injector.get(Logger);
logger.log('Injector car.drive() said: '+car.drive());
return car;
}
//#enddocregion injector
//#enddocregion

View File

@ -0,0 +1,24 @@
// Car without DI
import {Engine, Tires} from './car';
//#docregion car
export class Car {
//#docregion car-ctor
public engine: Engine;
public tires: Tires;
public description = 'No DI';
constructor() {
this.engine = new Engine();
this.tires = new Tires();
}
//#enddocregion car-ctor
// Method using the engine and tires
drive() {
return `${this.description} car with ` +
`${this.engine.cylinders} cylinders and ${this.tires.make} tires.`
}
}
//#enddocregion car

View File

@ -0,0 +1,37 @@
// #docregion
import { Component, Injector} from 'angular2/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 {
constructor(public car: Car) {}
factoryCar = (new CarFactory).createCar();
injectorCar = useInjector();
noDiCar = new CarNoDi;
simpleCar = simpleCar();
superCar = superCar();
testCar = testCar();
}

View File

@ -0,0 +1,32 @@
// #docregion
import {Injectable} from 'angular2/core';
// #docregion engine
export class Engine {
public cylinders = 4; // default
}
// #enddocregion engine
// #docregion tires
export class Tires {
public make = 'Flintstone';
public model = 'Square';
}
// #enddocregion tires
@Injectable()
// #docregion car
export class Car {
//#docregion car-ctor
public description = 'DI';
constructor(public engine: Engine, public tires: Tires) { }
// #enddocregion car-ctor
// Method using the engine and tires
drive() {
return `${this.description} car with ` +
`${this.engine.cylinders} cylinders and ${this.tires.make} tires.`
}
}
// #enddocregion car

View File

@ -0,0 +1,16 @@
// #docregion
import { Component } from 'angular2/core';
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
@Component({
selector: 'hero-list',
template: `
<div *ngFor="#hero of heroes">
{{hero.id}} - {{hero.name}}
</div>
`,
})
export class HeroListComponent {
heroes = HEROES;
}

View File

@ -0,0 +1,22 @@
// #docregion
import { Component } from 'angular2/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
@Component({
selector: 'hero-list',
template: `
<div *ngFor="#hero of heroes">
{{hero.id}} - {{hero.name}}
</div>
`,
})
export class HeroListComponent {
heroes: Hero[];
//#docregion ctor
constructor(heroService: HeroService) {
this.heroes = heroService.getHeroes();
}
//#enddocregion ctor
}

View File

@ -0,0 +1,23 @@
// #docregion
import { Component } from 'angular2/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
@Component({
selector: 'hero-list',
template: `
<div *ngFor="#hero of heroes">
{{hero.id}} - {{hero.name}}
({{hero.isSecret ? 'secret' : 'public'}})
</div>
`,
})
export class HeroListComponent {
heroes: Hero[];
//#docregion ctor-signature
constructor(heroService: HeroService) {
//#enddocregion ctor-signature
this.heroes = heroService.getHeroes();
}
}

View File

@ -0,0 +1,7 @@
// #docregion
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
export class HeroService {
getHeroes() { return HEROES; }
}

View File

@ -0,0 +1,16 @@
// #docregion
import {Injectable} from 'angular2/core';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
import {Logger} from '../logger.service';
@Injectable()
export class HeroService {
constructor(private _logger: Logger) { }
getHeroes() {
this._logger.log('Getting heroes ...')
return HEROES;
}
}

View File

@ -0,0 +1,19 @@
// #docregion
import {provide} from 'angular2/core';
import {HeroService} from './hero.service';
import {Logger} from '../logger.service';
import {UserService} from '../user.service';
// #docregion factory
let heroServiceFactory = (logger: Logger, userService: UserService) => {
return new HeroService(logger, userService.user.isAuthorized);
}
// #enddocregion factory
// #docregion provider
export let heroServiceProvider =
provide(HeroService, {
useFactory: heroServiceFactory,
deps: [Logger, UserService]
});
// #enddocregion provider

View File

@ -0,0 +1,22 @@
// #docregion
import {Injectable} from 'angular2/core';
import {Hero} from './hero';
import {HEROES} from './mock-heroes';
import {Logger} from '../logger.service';
@Injectable()
export class HeroService {
private _user:string;
// #docregion internals
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);
}
// #enddocregion internals
}

View File

@ -0,0 +1,6 @@
// #docregion
export class Hero {
id: number;
name: string;
isSecret = false;
}

View File

@ -0,0 +1,24 @@
// #docplaster
// #docregion
// #docregion v1
import { Component } from 'angular2/core';
import { HeroListComponent } from './hero-list.component';
// #enddocregion v1
import { HeroService } from './hero.service';
// #docregion v1
@Component({
selector: 'my-heroes',
template: `
<h2>Heroes</h2>
<hero-list></hero-list>
`,
// #enddocregion v1
// #docregion providers
providers:[HeroService],
// #enddocregion providers
// #docregion v1
directives:[HeroListComponent]
})
export class HeroesComponent { }
// #enddocregion v1

View File

@ -0,0 +1,15 @@
// #docregion
import { Component } from 'angular2/core';
import { HeroListComponent } from './hero-list.component';
import { heroServiceProvider} from './hero.service.provider';
@Component({
selector: 'my-heroes',
template: `
<h2>Heroes</h2>
<hero-list></hero-list>
`,
providers:[heroServiceProvider],
directives:[HeroListComponent]
})
export class HeroesComponent { }

View File

@ -0,0 +1,15 @@
// #docregion
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" }
];

View File

@ -0,0 +1,46 @@
// #docplaster
//#docregion
import {Component, Injector} from 'angular2/core';
import {Car, Engine, Tires} from './car/car';
import {HeroService} from './heroes/hero.service';
import {heroServiceProvider} from './heroes/hero.service.provider';
import {Logger} from './logger.service';
//#docregion injector
@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 {
constructor(private _injector: Injector) { }
car:Car = this._injector.get(Car);
//#docregion get-hero-service
heroService:HeroService = this._injector.get(HeroService);
//#enddocregion get-hero-service
hero = this.heroService.getHeroes()[0];
get rodent() {
let rous = this._injector.getOptional(ROUS);
if (rous) {
throw new Error('Aaaargh!')
}
return "R.O.U.S.'s? I don't think they exist!";
}
}
//#enddocregion injector
/**
* R.O.U.S. - Rodents Of Unusual Size
* // https://www.youtube.com/watch?v=BOv5ZjAOpC8
*/
class ROUS { }

View File

@ -0,0 +1,11 @@
// #docregion
import {Injectable} from 'angular2/core';
@Injectable()
export class Logger {
logs:string[] = []; // capture logs for testing
log(message: string){
this.logs.push(message);
console.log(message);
}
}

View File

@ -0,0 +1,8 @@
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {HeroService} from './heroes/hero.service';
//#docregion bootstrap
// Injecting services in bootstrap works but is discouraged
bootstrap(AppComponent, [HeroService]);
//#enddocregion bootstrap

View File

@ -0,0 +1,9 @@
//#docregion
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
import {ProvidersComponent} from './providers.component';
//#docregion bootstrap
bootstrap(AppComponent);
//#enddocregion bootstrap
bootstrap(ProvidersComponent);

View File

@ -0,0 +1,355 @@
// Examples of provider arrays
import { Component, Host, Inject, Injectable,
provide, Provider} from 'angular2/core';
import { APP_CONFIG,
Config, CONFIG } from './app.config';
import { HeroService} from './heroes/hero.service';
import { heroServiceProvider } from './heroes/hero.service.provider';
import { Logger } from './logger.service';
import { User, UserService } from './user.service';
let template = '{{log}}';
//////////////////////////////////////////
@Component({
selector: 'provider-1',
template: template,
providers:
//#docregion providers-1
[Logger]
//#enddocregion providers-1
})
export class ProviderComponent1 {
log:string;
constructor(logger: Logger) {
logger.log('Hello from logger provided with Logger class');
this.log = logger.logs[0];
}
}
//////////////////////////////////////////
@Component({
selector: 'provider-2',
template: template,
providers:
//#docregion providers-2
[new Provider(Logger, {useClass: Logger})]
//#enddocregion providers-2
})
export class ProviderComponent2 {
log:string;
constructor(logger: Logger) {
logger.log('Hello from logger provided with Provider class and useClass');
this.log = logger.logs[0];
}
}
//////////////////////////////////////////
@Component({
selector: 'provider-3',
template: template,
providers:
//#docregion providers-3
[provide(Logger, {useClass: Logger})]
//#enddocregion providers-3
})
export class ProviderComponent3 {
log:string;
constructor(logger: Logger) {
logger.log('Hello from logger provided with useClass');
this.log = logger.logs[0];
}
}
//////////////////////////////////////////
class BetterLogger extends Logger {}
@Component({
selector: 'provider-4',
template: template,
providers:
//#docregion providers-4
[provide(Logger, {useClass: BetterLogger})]
//#enddocregion providers-4
})
export class ProviderComponent4 {
log:string;
constructor(logger: Logger) {
logger.log('Hello from logger provided with useClass:BetterLogger');
this.log = logger.logs[0];
}
}
//////////////////////////////////////////
// #docregion EvenBetterLogger
@Injectable()
class EvenBetterLogger {
logs:string[] = [];
constructor(private _userService: UserService) { }
log(message:string){
message = `Message to ${this._userService.user.name}: ${message}.`;
console.log(message);
this.logs.push(message);
}
}
// #enddocregion EvenBetterLogger
@Component({
selector: 'provider-5',
template: template,
providers:
//#docregion providers-5
[
UserService,
provide(Logger, {useClass: EvenBetterLogger})
]
//#enddocregion providers-5
})
export class ProviderComponent5 {
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:
//#docregion providers-6a
[
NewLogger,
// Not aliased! Creates two instances of `NewLogger`
provide(OldLogger, {useClass:NewLogger})
]
//#enddocregion providers-6a
})
export class ProviderComponent6a {
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:
//#docregion providers-6b
[
NewLogger,
// Alias OldLogger w/ reference to NewLogger
provide(OldLogger, {useExisting: NewLogger})
]
//#enddocregion providers-6b
})
export class ProviderComponent6b {
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];
}
}
//////////////////////////////////////////
// #docregion silent-logger
// An object in the shape of the logger service
let silentLogger = {
logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'],
log: () => {}
}
// #enddocregion silent-logger
@Component({
selector: 'provider-7',
template: template,
providers:
//#docregion providers-7
[provide(Logger, {useValue: silentLogger})]
//#enddocregion providers-7
})
export class ProviderComponent7 {
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 ProviderComponent8{
// #docregion provider-8-ctor
constructor(heroService: HeroService){ }
// #enddocregion provider-8-ctor
// must be true else this component would have blown up at runtime
log = 'Hero service injected successfully'
}
/////////////////
@Component({
selector: 'provider-9a',
template: template,
providers:
/*
// #docregion providers-9a-interface
// FAIL! Can't use interface as provider token
[provide(Config, {useValue: CONFIG})]
// #enddocregion providers-9a-interface
*/
// #docregion providers-9a
// Use string as provider token
[provide('app.config', {useValue: CONFIG})]
// #enddocregion providers-9a
})
export class ProviderComponent9a {
log: string;
/*
// #docregion provider-9a-ctor-interface
// FAIL! Can't inject using the interface as the parameter type
constructor(private _config: Config){ }
// #enddocregion provider-9a-ctor-interface
*/
// #docregion provider-9a-ctor
// @Inject(token) to inject the dependency
constructor(@Inject('app.config') private _config: Config){ }
// #enddocregion provider-9a-ctor
ngOnInit() {
this.log = '"app.config" Application title is ' + this._config.title;
}
}
@Component({
selector: 'provider-9b',
template: template,
// #docregion providers-9b
providers:[provide(APP_CONFIG, {useValue: CONFIG})]
// #enddocregion providers-9b
})
export class ProviderComponent9b {
log: string;
// #docregion provider-9b-ctor
constructor(@Inject(APP_CONFIG) private _config: Config){ }
// #enddocregion provider-9b-ctor
ngOnInit() {
this.log = 'APP_CONFIG Application title is ' + this._config.title;
}
}
//////////////////////////////////////////
// Normal required logger
@Component({
selector: 'provider-10a',
template: template,
//#docregion providers-logger
providers: [Logger]
//#enddocregion providers-logger
})
export class ProviderComponent10a {
log:string;
constructor(logger: Logger) {
logger.log('Hello from the required logger.');
this.log = logger.logs[0];
}
}
// Optional logger
// #docregion import-optional
import {Optional} from 'angular2/core';
// #enddocregion import-optional
@Component({
selector: 'provider-10b',
template: template
})
export class ProviderComponent10b {
// #docregion provider-10-ctor
log:string;
constructor(@Optional() private _logger:Logger) { }
// #enddocregion provider-10-ctor
ngOnInit() {
// #docregion provider-10-logger
// No logger? Make one!
if (!this._logger) {
this._logger = {
log: (msg:string)=> this._logger.logs.push(msg),
logs: []
}
this._logger.log("Optional logger was not available.")
}
// #enddocregion provider-10-logger
else {
this._logger.log('Hello from the injected logger.')
this.log = this._logger.logs[0];
}
this.log = this._logger.logs[0];
}
}
/////////////////
@Component({
selector: 'my-providers',
template: `
<h2>Provider variations</h2>
<div id="p1"><provider-1></provider-1></div>
<div id="p2"><provider-2></provider-2></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="p9a"><provider-9a></provider-9a></div>
<div id="p9b"><provider-9b></provider-9b></div>
<div id="p10a"><provider-10a></provider-10a></div>
<div id="p10b"><provider-10b></provider-10b></div>
`,
directives:[
ProviderComponent1,
ProviderComponent2,
ProviderComponent3,
ProviderComponent4,
ProviderComponent5,
ProviderComponent6a,
ProviderComponent6b,
ProviderComponent7,
ProviderComponent8,
ProviderComponent9a,
ProviderComponent9b,
ProviderComponent10a,
ProviderComponent10b,
],
})
export class ProvidersComponent { }

View File

@ -0,0 +1,53 @@
// Simulate a simple test
// Reader should look to the testing chapter for the real thing
import {Component} from 'angular2/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() {
//#docregion spec
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);
})
//#enddocregion spec
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();
}

View File

@ -0,0 +1,23 @@
// #docregion
import {Injectable} from 'angular2/core';
@Injectable()
export class UserService {
// Todo: get the user; don't 'new' it.
private _alice = new User('Alice', true);
private _bob = new User('Bob', false);
// initial user is Bob
user = this._bob;
// swaps users
getNewUser() {
return this.user = this.user === this._bob ? this._alice : this._bob;
}
}
export class User {
constructor(
public name:string,
public isAuthorized:boolean = false) { }
}

View File

@ -0,0 +1,34 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<title>Dependency Injection</title>
<!-- IE required polyfills, in this exact order -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/main')
.then(null, console.error.bind(console));
</script>
</head>
<body>
<my-app>Loading my-app ...</my-app>
<my-providers>Loading my-providers ...</my-providers>
</body>
</html>

View File

@ -0,0 +1,9 @@
{
"description": "Dependency Injection",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1,2].*"
],
"tags": ["dependency", "di"]
}

View File

@ -0,0 +1,39 @@
System.register(['angular2/core'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1;
var HelloWorld;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
}],
execute: function() {
HelloWorld = (function () {
function HelloWorld() {
// Declaring the variable for binding with initial value
this.yourName = '';
}
HelloWorld = __decorate([
core_1.Component({
// Declare the tag name in index.html to where the component attaches
selector: 'hello-world',
// Location of the template for this component
templateUrl: 'app/hello_world.html'
}),
__metadata('design:paramtypes', [])
], HelloWorld);
return HelloWorld;
})();
exports_1("HelloWorld", HelloWorld);
}
}
});
//# sourceMappingURL=hello_world.js.map

View File

@ -0,0 +1,16 @@
System.register(['angular2/platform/browser', './hello_world'], function(exports_1) {
var browser_1, hello_world_1;
return {
setters:[
function (browser_1_1) {
browser_1 = browser_1_1;
},
function (hello_world_1_1) {
hello_world_1 = hello_world_1_1;
}],
execute: function() {
browser_1.bootstrap(hello_world_1.HelloWorld);
}
}
});
//# sourceMappingURL=main.js.map

View File

@ -0,0 +1,56 @@
System.register(['angular2/core', './ui_tabs'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1, ui_tabs_1;
var Detail, DiDemo;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
},
function (ui_tabs_1_1) {
ui_tabs_1 = ui_tabs_1_1;
}],
execute: function() {
Detail = (function () {
function Detail() {
}
return Detail;
})();
DiDemo = (function () {
function DiDemo() {
this.details = [];
this.id = 0;
}
DiDemo.prototype.addDetail = function () {
this.id++;
this.details.push({
title: "Detail " + this.id,
text: "Some detail text for " + this.id + "..."
});
};
DiDemo.prototype.removeDetail = function (detail) {
this.details = this.details.filter(function (d) { return d !== detail; });
};
DiDemo = __decorate([
core_1.Component({
selector: 'di-demo',
template: "\n <h4>Tabs Demo</h4>\n <ui-tabs>\n <template ui-pane title='Overview' active=\"true\">\n You have {{details.length}} details.\n </template>\n <template *ngFor=\"#detail of details\" ui-pane [title]=\"detail.title\">\n {{detail.text}} <br><br>\n <button class=\"btn\" (click)=\"removeDetail(detail)\">Remove</button>\n </template>\n <template ui-pane title='Summary'>\n Next last ID is {{id}}.\n </template>\n </ui-tabs>\n <hr>\n <button class=\"btn\" (click)=\"addDetail()\">Add Detail</button>\n ",
directives: [ui_tabs_1.UiTabs, ui_tabs_1.UiPane]
}),
__metadata('design:paramtypes', [])
], DiDemo);
return DiDemo;
})();
exports_1("DiDemo", DiDemo);
}
}
});
//# sourceMappingURL=di_demo.js.map

View File

@ -0,0 +1,16 @@
System.register(['angular2/platform/browser', './di_demo'], function(exports_1) {
var browser_1, di_demo_1;
return {
setters:[
function (browser_1_1) {
browser_1 = browser_1_1;
},
function (di_demo_1_1) {
di_demo_1 = di_demo_1_1;
}],
execute: function() {
browser_1.bootstrap(di_demo_1.DiDemo);
}
}
});
//# sourceMappingURL=main.js.map

View File

@ -0,0 +1,85 @@
System.register(['angular2/core'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1;
var UiPane, UiTabs;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
}],
execute: function() {
UiPane = (function () {
function UiPane(viewContainer, templateRef) {
this.viewContainer = viewContainer;
this.templateRef = templateRef;
this._active = false;
}
Object.defineProperty(UiPane.prototype, "active", {
get: function () {
return this._active;
},
set: function (active) {
if (active == this._active)
return;
this._active = active;
if (active) {
this.viewContainer.createEmbeddedView(this.templateRef);
}
else {
this.viewContainer.remove(0);
}
},
enumerable: true,
configurable: true
});
__decorate([
core_1.Input(),
__metadata('design:type', String)
], UiPane.prototype, "title", void 0);
__decorate([
core_1.Input(),
__metadata('design:type', Boolean),
__metadata('design:paramtypes', [Boolean])
], UiPane.prototype, "active", null);
UiPane = __decorate([
core_1.Directive({
selector: '[ui-pane]'
}),
__metadata('design:paramtypes', [core_1.ViewContainerRef, core_1.TemplateRef])
], UiPane);
return UiPane;
})();
exports_1("UiPane", UiPane);
UiTabs = (function () {
function UiTabs() {
}
UiTabs.prototype.select = function (pane) {
this.panes.toArray().forEach(function (p) { return p.active = p == pane; });
};
__decorate([
core_1.ContentChildren(UiPane),
__metadata('design:type', core_1.QueryList)
], UiTabs.prototype, "panes", void 0);
UiTabs = __decorate([
core_1.Component({
selector: 'ui-tabs',
template: "\n <ul class=\"nav nav-tabs\">\n <li *ngFor=\"var pane of panes\"\n (click)=\"select(pane)\"\n role=\"presentation\" [class.active]=\"pane.active\">\n <a>{{pane.title}}</a>\n </li>\n </ul>\n <ng-content></ng-content>\n ",
styles: ['a { cursor: pointer; cursor: hand; }']
}),
__metadata('design:paramtypes', [])
], UiTabs);
return UiTabs;
})();
exports_1("UiTabs", UiTabs);
}
}
});
//# sourceMappingURL=ui_tabs.js.map

View File

@ -0,0 +1,16 @@
System.register(['angular2/platform/browser', './todo_app'], function(exports_1) {
var browser_1, todo_app_1;
return {
setters:[
function (browser_1_1) {
browser_1 = browser_1_1;
},
function (todo_app_1_1) {
todo_app_1 = todo_app_1_1;
}],
execute: function() {
browser_1.bootstrap(todo_app_1.TodoApp);
}
}
});
//# sourceMappingURL=main.js.map

View File

@ -0,0 +1,8 @@
System.register([], function(exports_1) {
return {
setters:[],
execute: function() {
}
}
});
//# sourceMappingURL=todo.js.map

View File

@ -0,0 +1,66 @@
System.register(['angular2/core', './todo_list', './todo_form'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1, todo_list_1, todo_form_1;
var TodoApp;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
},
function (todo_list_1_1) {
todo_list_1 = todo_list_1_1;
},
function (todo_form_1_1) {
todo_form_1 = todo_form_1_1;
}],
execute: function() {
TodoApp = (function () {
function TodoApp() {
this.todos = [
{ text: 'learn angular', done: true },
{ text: 'build an angular app', done: false }
];
}
Object.defineProperty(TodoApp.prototype, "remaining", {
get: function () {
return this.todos.reduce(function (count, todo) { return count + +!todo.done; }, 0);
},
enumerable: true,
configurable: true
});
TodoApp.prototype.archive = function () {
var _this = this;
var oldTodos = this.todos;
this.todos = [];
oldTodos.forEach(function (todo) {
if (!todo.done)
_this.todos.push(todo);
});
};
TodoApp.prototype.addTask = function (task) {
this.todos.push(task);
};
TodoApp = __decorate([
core_1.Component({
selector: 'todo-app',
template: "\n <h2>Todo</h2>\n <span>{{remaining}} of {{todos.length}} remaining</span>\n [ <a (click)=\"archive()\">archive</a> ]\n\n <todo-list [todos]=\"todos\"></todo-list>\n <todo-form (newTask)=\"addTask($event)\"></todo-form>",
styles: ['a { cursor: pointer; cursor: hand; }'],
directives: [todo_list_1.TodoList, todo_form_1.TodoForm]
}),
__metadata('design:paramtypes', [])
], TodoApp);
return TodoApp;
})();
exports_1("TodoApp", TodoApp);
}
}
});
//# sourceMappingURL=todo_app.js.map

View File

@ -0,0 +1,47 @@
System.register(['angular2/core'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1;
var TodoForm;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
}],
execute: function() {
TodoForm = (function () {
function TodoForm() {
this.newTask = new core_1.EventEmitter();
this.task = '';
}
TodoForm.prototype.addTodo = function () {
if (this.task) {
this.newTask.next({ text: this.task, done: false });
}
this.task = '';
};
__decorate([
core_1.Output(),
__metadata('design:type', Object)
], TodoForm.prototype, "newTask", void 0);
TodoForm = __decorate([
core_1.Component({
selector: 'todo-form',
template: "\n <form (ngSubmit)=\"addTodo()\">\n <input type=\"text\" [(ngModel)]=\"task\" size=\"30\"\n placeholder=\"add new todo here\">\n <input class=\"btn-primary\" type=\"submit\" value=\"add\">\n </form>"
}),
__metadata('design:paramtypes', [])
], TodoForm);
return TodoForm;
})();
exports_1("TodoForm", TodoForm);
}
}
});
//# sourceMappingURL=todo_form.js.map

View File

@ -0,0 +1,41 @@
System.register(['angular2/core'], function(exports_1) {
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var core_1;
var TodoList;
return {
setters:[
function (core_1_1) {
core_1 = core_1_1;
}],
execute: function() {
TodoList = (function () {
function TodoList() {
}
__decorate([
core_1.Input(),
__metadata('design:type', Array)
], TodoList.prototype, "todos", void 0);
TodoList = __decorate([
core_1.Component({
selector: 'todo-list',
styles: ["\n .done-true {\n text-decoration: line-through;\n color: grey;\n }"
],
template: "\n <ul class=\"unstyled\">\n <li *ngFor=\"#todo of todos\">\n <input type=\"checkbox\" [(ngModel)]=\"todo.done\">\n <span class=\"done-{{todo.done}}\">{{todo.text}}</span>\n </li>\n </ul>"
}),
__metadata('design:paramtypes', [])
], TodoList);
return TodoList;
})();
exports_1("TodoList", TodoList);
}
}
});
//# sourceMappingURL=todo_list.js.map

File diff suppressed because it is too large Load Diff