From 1644673d6c9be60ec5e420b544cb3fa6a971d206 Mon Sep 17 00:00:00 2001 From: Torgeir Helgevold Date: Mon, 16 May 2016 21:56:13 -0400 Subject: [PATCH] docs(dependency-injection): show providers using map literals --- .../cb-dependency-injection/e2e-spec.js | 16 ++- .../ts/app/app.component.html | 5 +- .../ts/app/app.component.ts | 11 +- .../hero-of-the-month-literals.component.ts | 67 ++++++++++ .../ts/app/hero-of-the-month.component.ts | 2 +- .../dependency-injection/e2e-spec.js | 5 + .../ts/app/providers.component.ts | 118 ++++++++++-------- .../latest/cookbook/dependency-injection.jade | 16 +++ .../ts/latest/guide/dependency-injection.jade | 15 ++- 9 files changed, 193 insertions(+), 62 deletions(-) create mode 100644 public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month-literals.component.ts diff --git a/public/docs/_examples/cb-dependency-injection/e2e-spec.js b/public/docs/_examples/cb-dependency-injection/e2e-spec.js index aeb0e68b17..14f1f0994b 100644 --- a/public/docs/_examples/cb-dependency-injection/e2e-spec.js +++ b/public/docs/_examples/cb-dependency-injection/e2e-spec.js @@ -34,11 +34,16 @@ describe('Dependency Injection Cookbook', function () { expect(sortedHero).toBeDefined(); }); - it('should render Hero of the Month', function () { + it('should render Hero of the Month when DI deps are defined using provide()', function () { var heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0); expect(heroOfTheMonth).toBeDefined(); }); + it('should render Hero of the Month when DI deps are defined using provide object literal', function () { + var heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month 2"]')).get(0); + expect(heroOfTheMonth).toBeDefined(); + }); + it('should render Hero Bios', function () { var heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0); expect(heroBios).toBeDefined(); @@ -54,8 +59,13 @@ describe('Dependency Injection Cookbook', function () { expect(magmaPhone).toBeDefined(); }); - it('should render Hero-of-the-Month runner-ups', function () { - var runnersUp = element(by.id('rups')).getText(); + it('should render Hero-of-the-Month runner-ups when DI deps are defined using provide()', function () { + var runnersUp = element(by.id('rups1')).getText(); + expect(runnersUp).toContain('RubberMan, Mr. Nice'); + }); + + it('should render Hero-of-the-Month runner-ups when DI deps are defined using provide object literal', function () { + var runnersUp = element(by.id('rups2')).getText(); expect(runnersUp).toContain('RubberMan, Mr. Nice'); }); diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/app.component.html b/public/docs/_examples/cb-dependency-injection/ts/app/app.component.html index c27281f2af..0e1d15932d 100644 --- a/public/docs/_examples/cb-dependency-injection/ts/app/app.component.html +++ b/public/docs/_examples/cb-dependency-injection/ts/app/app.component.html @@ -23,6 +23,9 @@ +
+ +

Unsorted Heroes

@@ -36,4 +39,4 @@
-
\ No newline at end of file +
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/app.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/app.component.ts index f8194783d3..7188e4f63f 100644 --- a/public/docs/_examples/cb-dependency-injection/ts/app/app.component.ts +++ b/public/docs/_examples/cb-dependency-injection/ts/app/app.component.ts @@ -9,10 +9,13 @@ import { HeroesBaseComponent, import { HighlightDirective } from './highlight.directive'; import { ParentFinderComponent } from './parent-finder.component'; +// Object Literal syntax +import { HeroOfTheMonthLiteralsComponent } from './hero-of-the-month-literals.component'; + const DIRECTIVES = [ HeroBiosComponent, HeroBiosAndContactsComponent, HeroesBaseComponent, SortedHeroesComponent, - HeroOfTheMonthComponent, + HeroOfTheMonthComponent, HeroOfTheMonthLiteralsComponent, HighlightDirective, ParentFinderComponent ]; @@ -24,7 +27,7 @@ import { UserService } from './user.service'; @Component({ selector: 'my-app', - templateUrl:'app/app.component.html', + templateUrl: 'app/app.component.html', directives: DIRECTIVES, // #docregion providers providers: [LoggerService, UserContextService, UserService] @@ -33,10 +36,10 @@ import { UserService } from './user.service'; export class AppComponent { // #enddocregion import-services - private userId:number = 1; + private userId: number = 1; // #docregion ctor - constructor(logger:LoggerService, public userContext:UserContextService) { + constructor(logger: LoggerService, public userContext: UserContextService) { userContext.loadUser(this.userId); logger.logInfo('AppComponent initialized'); } diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month-literals.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month-literals.component.ts new file mode 100644 index 0000000000..13c6c0ab9d --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month-literals.component.ts @@ -0,0 +1,67 @@ +/* tslint:disable:one-line:check-open-brace*/ +// #docplaster +// #docregion opaque-token +import { OpaqueToken } from '@angular/core'; + +export const TITLE = new OpaqueToken('title'); +// #enddocregion opaque-token + +// #docregion hero-of-the-month +import { Component, Inject } from '@angular/core'; + +import { DateLoggerService, + MinimalLogger } from './date-logger.service'; +import { Hero } from './hero'; +import { HeroService } from './hero.service'; +import { LoggerService } from './logger.service'; +import { RUNNERS_UP, + runnersUpFactory } from './runners-up'; + +// #enddocregion hero-of-the-month +// #docregion some-hero +const someHero = new Hero(42, 'Magma', 'Had a great month!', '555-555-5555'); +// #enddocregion some-hero + +const template = ` +

{{title}}

+
Winner: {{heroOfTheMonth.name}}
+
Reason for award: {{heroOfTheMonth.description}}
+
Runners-up: {{runnersUp}}
+ +

Logs:

+
+
{{log}}
+
+ `; + +// #docregion hero-of-the-month +@Component({ + selector: 'hero-of-the-month-lit', + template: template, + // #docregion providers-using-object-literals + providers: [ + {provide: Hero, useValue: someHero}, + {provide: TITLE, useValue: 'Hero of the Month - Object Literals'}, + {provide: HeroService, useClass: HeroService}, + {provide: LoggerService, useClass: DateLoggerService}, + {provide: MinimalLogger, useExisting: LoggerService}, + {provide: RUNNERS_UP, useFactory: runnersUpFactory(2), deps: [Hero, HeroService]} + ] + // #enddocregion providers-using-object-literals +}) +export class HeroOfTheMonthLiteralsComponent { + logs: string[] = []; + +// #docregion ctor-signature + constructor( + logger: MinimalLogger, + public heroOfTheMonth: Hero, + @Inject(RUNNERS_UP) public runnersUp: string, + @Inject(TITLE) public title: string) +// #enddocregion ctor-signature + { + this.logs = logger.logs; + logger.logInfo('starting up'); + } +} +// #enddocregion hero-of-the-month diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts index 6b9646d3e9..4183734753 100644 --- a/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts +++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts @@ -26,7 +26,7 @@ const template = `

{{title}}

Winner: {{heroOfTheMonth.name}}
Reason for award: {{heroOfTheMonth.description}}
-
Runners-up: {{runnersUp}}
+
Runners-up: {{runnersUp}}

Logs:

diff --git a/public/docs/_examples/dependency-injection/e2e-spec.js b/public/docs/_examples/dependency-injection/e2e-spec.js index 819b8b0008..effdc1111f 100644 --- a/public/docs/_examples/dependency-injection/e2e-spec.js +++ b/public/docs/_examples/dependency-injection/e2e-spec.js @@ -88,6 +88,11 @@ describe('Dependency Injection Tests', function () { expectedMsg = 'Hello from logger provided with useClass'; expect(element(by.css('#p3')).getText()).toEqual(expectedMsg); }); + + it('P3a (provide) displays as expected', function () { + expectedMsg = 'Hello from logger provided with {provide: Logger, useClass: Logger}'; + expect(element(by.css('#p3a')).getText()).toEqual(expectedMsg); + }); it('P4 (useClass:BetterLogger) displays as expected', function () { expectedMsg = 'Hello from logger provided with useClass:BetterLogger'; diff --git a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts b/public/docs/_examples/dependency-injection/ts/app/providers.component.ts index e0426ae9d0..cd718c4c04 100644 --- a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts +++ b/public/docs/_examples/dependency-injection/ts/app/providers.component.ts @@ -1,6 +1,7 @@ +/* tslint:disable:one-line:check-open-brace*/ // Examples of provider arrays -//#docplaster -import { Component, Host, Inject, Injectable, +// #docplaster +import { Component, Inject, Injectable, provide, Provider } from '@angular/core'; import { APP_CONFIG, @@ -9,7 +10,7 @@ import { 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'; +import { UserService } from './user.service'; let template = '{{log}}'; @@ -18,12 +19,12 @@ let template = '{{log}}'; selector: 'provider-1', template: template, providers: - //#docregion providers-1 + // #docregion providers-1 [Logger] - //#enddocregion providers-1 + // #enddocregion providers-1 }) export class ProviderComponent1 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from logger provided with Logger class'); this.log = logger.logs[0]; @@ -35,12 +36,12 @@ export class ProviderComponent1 { selector: 'provider-2', template: template, providers: - //#docregion providers-2 + // #docregion providers-2 [new Provider(Logger, {useClass: Logger})] - //#enddocregion providers-2 + // #enddocregion providers-2 }) export class ProviderComponent2 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from logger provided with Provider class and useClass'); this.log = logger.logs[0]; @@ -52,18 +53,35 @@ export class ProviderComponent2 { selector: 'provider-3', template: template, providers: - //#docregion providers-3 + // #docregion providers-3 [provide(Logger, {useClass: Logger})] - //#enddocregion providers-3 + // #enddocregion providers-3 }) export class ProviderComponent3 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from logger provided with useClass'); this.log = logger.logs[0]; } } +////////////////////////////////////////// +@Component({ + selector: 'provider-3a', + template: template, + providers: + // #docregion providers-3a + [{provide: Logger, useClass: Logger}] + // #enddocregion providers-3a +}) +export class ProviderComponent3a { + log: string; + constructor(logger: Logger) { + logger.log('Hello from logger provided with {provide: Logger, useClass: Logger}'); + this.log = logger.logs[0]; + } +} + ////////////////////////////////////////// class BetterLogger extends Logger {} @@ -71,12 +89,12 @@ class BetterLogger extends Logger {} selector: 'provider-4', template: template, providers: - //#docregion providers-4 + // #docregion providers-4 [provide(Logger, {useClass: BetterLogger})] - //#enddocregion providers-4 + // #enddocregion providers-4 }) export class ProviderComponent4 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from logger provided with useClass:BetterLogger'); this.log = logger.logs[0]; @@ -87,11 +105,11 @@ export class ProviderComponent4 { // #docregion EvenBetterLogger @Injectable() class EvenBetterLogger { - logs:string[] = []; + logs: string[] = []; constructor(private userService: UserService) { } - log(message:string){ + log(message: string){ message = `Message to ${this.userService.user.name}: ${message}.`; console.log(message); this.logs.push(message); @@ -103,13 +121,13 @@ class EvenBetterLogger { selector: 'provider-5', template: template, providers: - //#docregion providers-5 + // #docregion providers-5 [ UserService, provide(Logger, {useClass: EvenBetterLogger}) ] - //#enddocregion providers-5 + // #enddocregion providers-5 }) export class ProviderComponent5 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from EvenBetterlogger'); this.log = logger.logs[0]; @@ -119,9 +137,9 @@ export class ProviderComponent5 { ////////////////////////////////////////// class NewLogger extends Logger {} class OldLogger { - logs:string[] = []; - log(message:string) { - throw new Error('Should not call the old logger!') + logs: string[] = []; + log(message: string) { + throw new Error('Should not call the old logger!'); }; } @@ -129,15 +147,15 @@ class OldLogger { selector: 'provider-6a', template: template, providers: - //#docregion providers-6a + // #docregion providers-6a [ NewLogger, // Not aliased! Creates two instances of `NewLogger` - provide(OldLogger, {useClass:NewLogger}) ] - //#enddocregion providers-6a + provide(OldLogger, {useClass: NewLogger}) ] + // #enddocregion providers-6a }) export class ProviderComponent6a { - log:string; - constructor(newLogger:NewLogger, oldLogger: OldLogger) { + log: string; + constructor(newLogger: NewLogger, oldLogger: OldLogger) { if (newLogger === oldLogger){ throw new Error('expected the two loggers to be different instances'); } @@ -152,15 +170,15 @@ export class ProviderComponent6a { selector: 'provider-6b', template: template, providers: - //#docregion providers-6b + // #docregion providers-6b [ NewLogger, // Alias OldLogger w/ reference to NewLogger provide(OldLogger, {useExisting: NewLogger}) ] - //#enddocregion providers-6b + // #enddocregion providers-6b }) export class ProviderComponent6b { - log:string; - constructor(newLogger:NewLogger, oldLogger: OldLogger) { + log: string; + constructor(newLogger: NewLogger, oldLogger: OldLogger) { if (newLogger !== oldLogger){ throw new Error('expected the two loggers to be the same instance'); } @@ -175,19 +193,19 @@ export class ProviderComponent6b { let silentLogger = { logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'], log: () => {} -} +}; // #enddocregion silent-logger @Component({ selector: 'provider-7', template: template, providers: - //#docregion providers-7 + // #docregion providers-7 [provide(Logger, {useValue: silentLogger})] - //#enddocregion providers-7 + // #enddocregion providers-7 }) export class ProviderComponent7 { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from logger provided with useValue'); this.log = logger.logs[0]; @@ -198,7 +216,7 @@ export class ProviderComponent7 { @Component({ selector: 'provider-8', template: template, - providers:[heroServiceProvider, Logger, UserService] + providers: [heroServiceProvider, Logger, UserService] }) export class ProviderComponent8{ // #docregion provider-8-ctor @@ -206,7 +224,7 @@ export class ProviderComponent8{ // #enddocregion provider-8-ctor // must be true else this component would have blown up at runtime - log = 'Hero service injected successfully' + log = 'Hero service injected successfully'; } ///////////////// @@ -248,7 +266,7 @@ export class ProviderComponent9a { selector: 'provider-9b', template: template, // #docregion providers-9b - providers:[provide(APP_CONFIG, {useValue: CONFIG})] + providers: [provide(APP_CONFIG, {useValue: CONFIG})] // #enddocregion providers-9b }) export class ProviderComponent9b { @@ -266,12 +284,12 @@ export class ProviderComponent9b { @Component({ selector: 'provider-10a', template: template, - //#docregion providers-logger + // #docregion providers-logger providers: [Logger] - //#enddocregion providers-logger + // #enddocregion providers-logger }) export class ProviderComponent10a { - log:string; + log: string; constructor(logger: Logger) { logger.log('Hello from the required logger.'); this.log = logger.logs[0]; @@ -289,8 +307,8 @@ import {Optional} from '@angular/core'; }) export class ProviderComponent10b { // #docregion provider-10-ctor - log:string; - constructor(@Optional() private logger:Logger) { } + log: string; + constructor(@Optional() private logger: Logger) { } // #enddocregion provider-10-ctor ngOnInit() { @@ -298,16 +316,16 @@ export class ProviderComponent10b { // No logger? Make one! if (!this.logger) { this.logger = { - log: (msg:string)=> this.logger.logs.push(msg), + log: (msg: string) => this.logger.logs.push(msg), logs: [] - } + }; // #enddocregion provider-10-logger - this.logger.log("Optional logger was not available.") + this.logger.log('Optional logger was not available.'); // #docregion provider-10-logger } // #enddocregion provider-10-logger else { - this.logger.log('Hello from the injected logger.') + this.logger.log('Hello from the injected logger.'); this.log = this.logger.logs[0]; } this.log = this.logger.logs[0]; @@ -322,6 +340,7 @@ export class ProviderComponent10b {
+
@@ -333,10 +352,11 @@ export class ProviderComponent10b {
`, - directives:[ + directives: [ ProviderComponent1, ProviderComponent2, ProviderComponent3, + ProviderComponent3a, ProviderComponent4, ProviderComponent5, ProviderComponent6a, diff --git a/public/docs/ts/latest/cookbook/dependency-injection.jade b/public/docs/ts/latest/cookbook/dependency-injection.jade index e15af274c9..62fbeacf3c 100644 --- a/public/docs/ts/latest/cookbook/dependency-injection.jade +++ b/public/docs/ts/latest/cookbook/dependency-injection.jade @@ -28,6 +28,8 @@ include ../_util-fns * [useClass - the *class provider*](#useclass) * [useExisting - the *alias provider*](#useexisting) * [useFactory - the *factory provider*](#usefactory) + + [Define providers with object literals](#object-literals) [Provider token alternatives](#tokens) * [class-interface](#class-interface) @@ -541,6 +543,20 @@ a(id='usefactory') Look at the [live example](/resources/live-examples/cb-dependency-injection/ts/plnkr.html) for the full source code. + +.l-main-section +:marked + ## Define providers with object literals + +:marked + In the previous section we learned to use the `provide` method to customize how dependencies are created. + + Instead of calling the `provide` function, we can configure providers with _object literals_. + It's a slightly more concise syntax and we don't have to import the `provide` function. + + Here's a set of providers that we saw earlier, re-written with object literals. + ++makeExample('cb-dependency-injection/ts/app/hero-of-the-month-literals.component.ts','providers-using-object-literals')(format='.') a(id="tokens") .l-main-section diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade index 5a185c6941..b5ea6f6f80 100644 --- a/public/docs/ts/latest/guide/dependency-injection.jade +++ b/public/docs/ts/latest/guide/dependency-injection.jade @@ -569,14 +569,20 @@ code-example(format, language="html"). // #docregion providers-provide-3 // Skip for Dart, where the provide() function won't pass type checking. :marked - The [provide](../api/core/provide-function.html) function is the more common, friendlier way to create a `Provider`: + The [provide](../api/core/provide-function.html) function is the typical way to create a `Provider`: // #enddocregion providers-provide-3 +makeExample('dependency-injection/ts/app/providers.component.ts','providers-3') // #docregion providers-provide-4-1 // Modified for Dart. + :marked - In both approaches — `Provider` class and `provide` function — - we supply two arguments. + Or we can declare a provider in an _object literal_ and skip the `provide` function. ++makeExample('dependency-injection/ts/app/providers.component.ts','providers-3a') + +:marked + Pick the syntax that you prefer. They all do the same thing. + + In each syntax, we supply two types of values. // #enddocregion providers-provide-4-1 // #docregion providers-provide-4-2 :marked @@ -589,6 +595,7 @@ code-example(format, language="html"). The second is a provider definition object, which we can think of as a *recipe* for creating the dependency value. There are many ways to create dependency values... and many ways to write a recipe. + // #docregion providers-alternative-1 :marked @@ -606,7 +613,7 @@ code-example(format, language="html"). This logger gets the user from the injected `UserService`, which happens also to be injected at the application level. // #enddocregion providers-alternative-2 -+makeExample('dependency-injection/ts/app/providers.component.ts','EvenBetterLogger') ++makeExample('dependency-injection/ts/app/providers.component.ts','EvenBetterLogger')(format='.') // #docregion providers-alternative-3 :marked Configure it like we did `BetterLogger`.