docs(di): update docs on di

This commit is contained in:
Tobias Bosch 2016-09-14 09:43:01 -07:00
parent d299ce4bcf
commit 0a2132ef10
7 changed files with 526 additions and 377 deletions

View File

@ -22,6 +22,23 @@ class _NullInjector implements Injector {
} }
/** /**
* @whatItDoes Injector interface
* @howToUse
* ```
* const injector: Injector = ...;
* injector.get(...);
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/injector_spec.ts region='Injector'}
*
* `Injector` returns itself when given `Injector` as a token:
* {@example core/di/ts/injector_spec.ts region='injectInjector'}
*
* @stable * @stable
*/ */
export abstract class Injector { export abstract class Injector {
@ -34,22 +51,6 @@ export abstract class Injector {
* - Throws {@link NoProviderError} if no `notFoundValue` that is not equal to * - Throws {@link NoProviderError} if no `notFoundValue` that is not equal to
* Injector.THROW_IF_NOT_FOUND is given * Injector.THROW_IF_NOT_FOUND is given
* - Returns the `notFoundValue` otherwise * - Returns the `notFoundValue` otherwise
*
* ### Example ([live demo](http://plnkr.co/edit/HeXSHg?p=preview))
*
* ```typescript
* var injector = ReflectiveInjector.resolveAndCreate([
* {provide: "validToken", useValue: "Value"}
* ]);
* expect(injector.get("validToken")).toEqual("Value");
* expect(() => injector.get("invalidToken")).toThrowError();
* ```
*
* `Injector` returns itself when given `Injector` as a token.
*
* ```typescript
* var injector = ReflectiveInjector.resolveAndCreate([]);
* expect(injector.get(Injector)).toBe(injector);
* ``` * ```
*/ */
get(token: any, notFoundValue?: any): any { return unimplemented(); } get(token: any, notFoundValue?: any): any { return unimplemented(); }

View File

@ -16,45 +16,29 @@ import {makeParamDecorator} from '../util/decorators';
*/ */
export interface InjectDecorator { export interface InjectDecorator {
/** /**
* A parameter metadata that specifies a dependency. * @whatItDoes A parameter decorator that specifies a dependency.
* * @howToUse
* ### Example ([live demo](http://plnkr.co/edit/6uHYJK?p=preview)) * ```
*
* ```typescript
* class Engine {}
*
* @Injectable() * @Injectable()
* class Car { * class Car {
* engine; * constructor(@Inject("MyEngine") public engine:Engine) {}
* constructor(@Inject("MyEngine") engine:Engine) {
* this.engine = engine;
* }
* } * }
*
* var injector = Injector.resolveAndCreate([
* {provide: "MyEngine", useClass: Engine},
* Car
* ]);
*
* expect(injector.get(Car).engine instanceof Engine).toBe(true);
* ``` * ```
* *
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/metadata_spec.ts region='Inject'}
*
* When `@Inject()` is not present, {@link Injector} will use the type annotation of the * When `@Inject()` is not present, {@link Injector} will use the type annotation of the
* parameter. * parameter.
* *
* ### Example * ### Example
* *
* ```typescript * {@example core/di/ts/metadata_spec.ts region='InjectWithoutDecorator'}
* class Engine {}
* *
* @Injectable()
* class Car {
* constructor(public engine: Engine) {} //same as constructor(@Inject(Engine) engine:Engine)
* }
*
* var injector = Injector.resolveAndCreate([Engine, Car]);
* expect(injector.get(Car).engine instanceof Engine).toBe(true);
* ```
* @stable * @stable
*/ */
(token: any): any; (token: any): any;
@ -84,25 +68,23 @@ export const Inject: InjectDecorator = makeParamDecorator('Inject', [['token', u
*/ */
export interface OptionalDecorator { export interface OptionalDecorator {
/** /**
* A parameter metadata that marks a dependency as optional. {@link Injector} provides `null` if * @whatItDoes A parameter metadata that marks a dependency as optional.
* the dependency is not found. * {@link Injector} provides `null` if the dependency is not found.
* * @howToUse
* ### Example ([live demo](http://plnkr.co/edit/AsryOm?p=preview)) * ```
*
* ```typescript
* class Engine {}
*
* @Injectable() * @Injectable()
* class Car { * class Car {
* engine; * constructor(@Optional() public engine:Engine) {}
* constructor(@Optional() engine:Engine) {
* this.engine = engine;
* }
* } * }
*
* var injector = Injector.resolveAndCreate([Car]);
* expect(injector.get(Car).engine).toBeNull();
* ``` * ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/metadata_spec.ts region='Optional'}
*
* @stable * @stable
*/ */
(): any; (): any;
@ -131,35 +113,25 @@ export const Optional: OptionalDecorator = makeParamDecorator('Optional', []);
*/ */
export interface InjectableDecorator { export interface InjectableDecorator {
/** /**
* A marker metadata that marks a class as available to {@link Injector} for creation. * @whatItDoes A marker metadata that marks a class as available to {@link Injector} for creation.
* * @howToUse
* ### Example ([live demo](http://plnkr.co/edit/Wk4DMQ?p=preview))
*
* ```typescript
* @Injectable()
* class UsefulService {}
*
* @Injectable()
* class NeedsService {
* constructor(public service:UsefulService) {}
* }
*
* var injector = Injector.resolveAndCreate([NeedsService, UsefulService]);
* expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true);
* ``` * ```
* @Injectable()
* class Car {}
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/metadata_spec.ts region='Injectable'}
*
* {@link Injector} will throw {@link NoAnnotationError} when trying to instantiate a class that * {@link Injector} will throw {@link NoAnnotationError} when trying to instantiate a class that
* does not have `@Injectable` marker, as shown in the example below. * does not have `@Injectable` marker, as shown in the example below.
* *
* ```typescript * {@example core/di/ts/metadata_spec.ts region='InjectableThrows'}
* class UsefulService {}
* *
* class NeedsService {
* constructor(public service:UsefulService) {}
* }
*
* var injector = Injector.resolveAndCreate([NeedsService, UsefulService]);
* expect(() => injector.get(NeedsService)).toThrowError();
* ```
* @stable * @stable
*/ */
(): any; (): any;
@ -188,31 +160,22 @@ export const Injectable: InjectableDecorator = makeParamDecorator('Injectable',
*/ */
export interface SelfDecorator { export interface SelfDecorator {
/** /**
* Specifies that an {@link Injector} should retrieve a dependency only from itself. * @whatItDoes Specifies that an {@link Injector} should retrieve a dependency only from itself.
* * @howToUse
* ### Example ([live demo](http://plnkr.co/edit/NeagAg?p=preview))
*
* ```typescript
* class Dependency {
* }
*
* @Injectable()
* class NeedsDependency {
* dependency;
* constructor(@Self() dependency:Dependency) {
* this.dependency = dependency;
* }
* }
*
* var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
* var nd = inj.get(NeedsDependency);
*
* expect(nd.dependency instanceof Dependency).toBe(true);
*
* var inj = Injector.resolveAndCreate([Dependency]);
* var child = inj.resolveAndCreateChild([NeedsDependency]);
* expect(() => child.get(NeedsDependency)).toThrowError();
* ``` * ```
* @Injectable()
* class Car {
* constructor(@Self() public engine:Engine) {}
* }
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/metadata_spec.ts region='Self'}
*
* @stable * @stable
*/ */
(): any; (): any;
@ -242,29 +205,22 @@ export const Self: SelfDecorator = makeParamDecorator('Self', []);
*/ */
export interface SkipSelfDecorator { export interface SkipSelfDecorator {
/** /**
* Specifies that the dependency resolution should start from the parent injector. * @whatItDoes Specifies that the dependency resolution should start from the parent injector.
* * @howToUse
* ### Example ([live demo](http://plnkr.co/edit/Wchdzb?p=preview))
*
* ```typescript
* class Dependency {
* }
*
* @Injectable()
* class NeedsDependency {
* dependency;
* constructor(@SkipSelf() dependency:Dependency) {
* this.dependency = dependency;
* }
* }
*
* var parent = Injector.resolveAndCreate([Dependency]);
* var child = parent.resolveAndCreateChild([NeedsDependency]);
* expect(child.get(NeedsDependency).dependency instanceof Depedency).toBe(true);
*
* var inj = Injector.resolveAndCreate([Dependency, NeedsDependency]);
* expect(() => inj.get(NeedsDependency)).toThrowError();
* ``` * ```
* @Injectable()
* class Car {
* constructor(@SkipSelf() public engine:Engine) {}
* }
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example
*
* {@example core/di/ts/metadata_spec.ts region='SkipSelf'}
*
* @stable * @stable
*/ */
(): any; (): any;
@ -293,56 +249,24 @@ export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf', []);
*/ */
export interface HostDecorator { export interface HostDecorator {
/** /**
* Specifies that an injector should retrieve a dependency from any injector until reaching the * @whatItDoes Specifies that an injector should retrieve a dependency from any injector until
* closest host. * reaching the
* * host element of the current component.
* In Angular, a component element is automatically declared as a host for all the injectors in * @howToUse
* its view. * ```
* * @Injectable()
* ### Example ([live demo](http://plnkr.co/edit/GX79pV?p=preview)) * class Car {
* * constructor(@Host() public engine:Engine) {}
* In the following example `App` contains `ParentCmp`, which contains `ChildDirective`.
* So `ParentCmp` is the host of `ChildDirective`.
*
* `ChildDirective` depends on two services: `HostService` and `OtherService`.
* `HostService` is defined at `ParentCmp`, and `OtherService` is defined at `App`.
*
*```typescript
* class OtherService {}
* class HostService {}
*
* @Directive({
* selector: 'child-directive'
* })
* class ChildDirective {
* constructor(@Optional() @Host() os:OtherService, @Optional() @Host() hs:HostService){
* console.log("os is null", os);
* console.log("hs is NOT null", hs);
* }
* } * }
* ```
* *
* @Component({ * @description
* selector: 'parent-cmp', * For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* providers: [HostService], *
* template: ` * ### Example
* Dir: <child-directive></child-directive> *
* `, * {@example core/di/ts/metadata_spec.ts region='Host'}
* directives: [ChildDirective]
* })
* class ParentCmp {
* }
* *
* @Component({
* selector: 'app',
* providers: [OtherService],
* template: `
* Parent: <parent-cmp></parent-cmp>
* `,
* directives: [ParentCmp]
* })
* class App {
* }
*```
* @stable * @stable
*/ */
(): any; (): any;

View File

@ -9,50 +9,45 @@
import {Type} from '../type'; import {Type} from '../type';
/** /**
* Configures the {@link Injector} to return an instance of `Type` when `Type' is used as token. * @whatItDoes Configures the {@link Injector} to return an instance of `Type` when `Type' is used
* as token.
* @howToUse
* ```
* @Injectable()
* class MyService {}
*
* const provider: TypeProvider = MyService;
* ```
*
* @description
* *
* Create an instance by invoking the `new` operator and supplying additional arguments. * Create an instance by invoking the `new` operator and supplying additional arguments.
* This form is a short form of `TypeProvider`; * This form is a short form of `TypeProvider`;
* *
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
*
* ### Example * ### Example
* ```javascript
* @Injectable()
* class Greeting {
* text: 'Hello';
* }
* *
* @Injectable() * {@example core/di/ts/provider_spec.ts region='TypeProvider'}
* class MyClass {
* greeting:string;
* constructor(greeting: Greeting) {
* this.greeting = greeting.text;
* }
* }
*
* const injector = Injector.resolveAndCreate([
* Greeting, // Shorthand for { provide: Greeting, useClass: Greeting }
* MyClass // Shorthand for { provide: MyClass, useClass: MyClass }
* ]);
*
* const myClass: MyClass = injector.get(MyClass);
* expect(myClass.greeting).toEqual('Hello');
* ```
* *
* @stable * @stable
*/ */
export interface TypeProvider extends Type<any> {} export interface TypeProvider extends Type<any> {}
/** /**
* Configures the {@link Injector} to return a value for a token. * @whatItDoes Configures the {@link Injector} to return a value for a token.
* @howToUse
* ```
* const provider: ValueProvider = {provide: 'someToken', useValue: 'someValue'};
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* *
* ### Example * ### Example
* ```javascript
* const injector = Injector.resolveAndCreate([
* {provide: String, useValue: 'Hello'}
* ]);
* *
* expect(injector.get(String)).toEqual('Hello'); * {@example core/di/ts/provider_spec.ts region='ValueProvider'}
* ``` *
* @stable * @stable
*/ */
export interface ValueProvider { export interface ValueProvider {
@ -71,62 +66,31 @@ export interface ValueProvider {
* providers spread across many files to provide configuration information to a common token. * providers spread across many files to provide configuration information to a common token.
* *
* ### Example * ### Example
* ```javascript
* var locale = new OpaqueToken('local');
* *
* const injector = Injector.resolveAndCreate([ * {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
* { provide: locale, multi: true, useValue: 'en' },
* { provide: locale, multi: true, useValue: 'sk' },
* ]);
*
* const locales: string[] = injector.get(locale);
* expect(locales).toEqual(['en', 'sk']);
* ```
*/ */
multi?: boolean; multi?: boolean;
} }
/** /**
* Configures the {@link Injector} to return an instance of `useClass` for a token. * @whatItDoes Configures the {@link Injector} to return an instance of `useClass` for a token.
* @howToUse
* ```
* @Injectable()
* class MyService {}
*
* const provider: ClassProvider = {provide: 'someToken', useClass: MyService};
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* *
* ### Example * ### Example
* ```javascript
* abstract class Shape {
* name: string;
* }
* *
* class Square extends Shape { * {@example core/di/ts/provider_spec.ts region='ClassProvider'}
* name = 'square';
* }
* *
* const injector = Injector.resolveAndCreate([ * Note that following two providers are not equal:
* {provide: Shape, useClass: Square} * {@example core/di/ts/provider_spec.ts region='ClassProviderDifference'}
* ]);
*
* const shape: Shape = injector.get(Shape);
* expect(shape.name).toEqual('square');
* expect(shape instanceof Square).toBe(true);
* ```
*
* Note that following is not equal:
* ```javascript
* class Greeting {
* salutation = 'Hello';
* }
*
* class FormalGreeting extends Greeting {
* salutation = 'Greetings';
* }
*
* const injector = Injector.resolveAndCreate([
* FormalGreeting,
* {provide: Greeting, useClass: FormalGreeting}
* ]);
*
* // The injector returns different instances.
* // See: {provide: ?, useExisting: ?} if you want the same instance.
* expect(injector.get(FormalGreeting)).not.toBe(injector.get(Greeting));
* ```
* *
* @stable * @stable
*/ */
@ -146,56 +110,26 @@ export interface ClassProvider {
* providers spread across many files to provide configuration information to a common token. * providers spread across many files to provide configuration information to a common token.
* *
* ### Example * ### Example
* ```javascript
* abstract class Locale {
* name: string;
* };
* *
* @Injectable() * {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
* class EnLocale extends Locale {
* name: 'en';
* };
*
* @Injectable()
* class SkLocale extends Locale {
* name: 'sk';
* };
*
* const injector = Injector.resolveAndCreate([
* { provide: Locale, useValue: EnLocale, multi: true },
* { provide: Locale, useValue: SkLocale, multi: true },
* ]);
*
* const locales: Locale[] = injector.get(Locale);
* const localeNames: string[] = locals.map((l) => l.name);
* expect(localeNames).toEqual(['en', 'sk']);
* ```
*/ */
multi?: boolean; multi?: boolean;
} }
/** /**
* Configures the {@link Injector} to return a value of another `useExisting` token. * @whatItDoes Configures the {@link Injector} to return a value of another `useExisting` token.
* @howToUse
* ```
* const provider: ExistingProvider = {provide: 'someToken', useExisting: 'someOtherToken'};
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* *
* ### Example * ### Example
* ```javascript
* class Greeting {
* salutation = 'Hello';
* }
* *
* class FormalGreeting extends Greeting { * {@example core/di/ts/provider_spec.ts region='ExistingProvider'}
* salutation = 'Greetings';
* }
* *
* const injector = Injector.resolveAndCreate([
* FormalGreeting,
* {provide: Greeting, useExisting: FormalGreeting}
* ]);
*
* expect(injector.get(Greeting).name).toEqual('Hello');
* expect(injector.get(FormalGreeting).name).toEqual('Hello');
* expect(injector.get(Salutation).name).toBe(injector.get(Greeting));
* ```
* @stable * @stable
*/ */
export interface ExistingProvider { export interface ExistingProvider {
@ -214,52 +148,32 @@ export interface ExistingProvider {
* providers spread across many files to provide configuration information to a common token. * providers spread across many files to provide configuration information to a common token.
* *
* ### Example * ### Example
* ```javascript
* abstract class Locale {
* name: string;
* };
* *
* @Injectable() * {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
* class EnLocale extends Locale {
* name: 'en';
* };
*
* @Injectable()
* class SkLocale extends Locale {
* name: 'sk';
* };
*
* const injector = Injector.resolveAndCreate([
* EnLocale,
* SkLocale
* { provide: Locale, useExisting: EnLocale, multi: true },
* { provide: Locale, useExisting: SkLocale, multi: true },
* ]);
*
* const locales: Locale[] = injector.get(Locale);
* const localeNames: string[] = locals.map((l) => l.name);
* expect(localeNames).toEqual(['en', 'sk']);
* ```
*/ */
multi?: boolean; multi?: boolean;
} }
/** /**
* Configures the {@link Injector} to return a value by invoking a `useFactory` function. * @whatItDoes Configures the {@link Injector} to return a value by invoking a `useFactory`
* function.
* @howToUse
* ```
* function serviceFactory() { ... }
*
* const provider: FactoryProvider = {provide: 'someToken', useFactory: serviceFactory, deps: []};
* ```
*
* @description
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* *
* ### Example * ### Example
* ```javascript
* const HASH = new OpaqueToken('hash');
* *
* const injector = Injector.resolveAndCreate([ * {@example core/di/ts/provider_spec.ts region='FactoryProvider'}
* {provide: Location, useValue: window.location},
* {provide: HASH, useFactory: (location: Location) => location.hash, deps: [Location]}
* ]);
* *
* Dependencies can also be marked as optional:
* {@example core/di/ts/provider_spec.ts region='FactoryProviderOptionalDeps'}
* *
* // Assume location is: http://angular.io/#someLocation
* expect(injector.get(HASH)).toEqual('someLocation');
* ```
* @stable * @stable
*/ */
export interface FactoryProvider { export interface FactoryProvider {
@ -285,65 +199,21 @@ export interface FactoryProvider {
* providers spread across many files to provide configuration information to a common token. * providers spread across many files to provide configuration information to a common token.
* *
* ### Example * ### Example
* ```javascript
* class Locale {
* constructor(public name: string) {}
* };
* const PRIMARY = new OpequeToken('primary');
* const SECONDARY = new OpequeToken('secondary');
* *
* const injector = Injector.resolveAndCreate([ * {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
* { provide: PRIMARY: useValue: 'en'},
* { provide: SECONDARY: useValue: 'sk'},
* { provide: Locale, useFactory: (n) => new Locale(n), deps: [PRIMARY], multi: true},
* { provide: Locale, useFactory: (n) => new Locale(n), deps: [SECONDARY], multi: true},
* ]);
*
* const locales: Locale[] = injector.get(Locale);
* const localeNames: string[] = locals.map((l) => l.name);
* expect(localeNames).toEqual(['en', 'sk']);
* ```
*/ */
multi?: boolean; multi?: boolean;
} }
/** /**
* Describes how the {@link Injector} should be configured. * @whatItDoes Describes how the {@link Injector} should be configured.
* * @howToUse
* See {@link TypeProvider}, {@link ValueProvider}, {@link ClassProvider}, {@link ExistingProvider}, * See {@link TypeProvider}, {@link ValueProvider}, {@link ClassProvider}, {@link ExistingProvider},
* {@link FactoryProvider}. * {@link FactoryProvider}.
* *
* ```javascript * @description
* class Greeting { * For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
* salutation = 'Hello';
* }
* *
* class FormalGreeting extends Greeting {
* salutation = 'Greetings';
* }
*
* abstract class Operation {
* apply(a,b): any;
* }
*
* class AddOperation extends Operation {
* apply(a,b) { return a+b; }
* }
*
*
* const injector = Injector.resolveAndCreate([
* FormalGreeting,
* {provide: String, useValue: 'Hello World!'},
* {provide: Greeting, useExisting: FormalGreeting},
* {provide: Operation, useClass: AddOperation},
* {provide: Number, useFactory: (op) =>op.apply(1,2), deps: [Operation] }
* ]);
*
* expect(injector.get(FormalGreeting).name).toEqual('Greetings');
* expect(injector.get(String).name).toEqual('Hello World!');
* expect(injector.get(Greeting).name).toBe(injector.get(FormalGreeting));
* expect(injector.get(Number).toEqual(3);
* ```
* @stable * @stable
*/ */
export type Provider = export type Provider =

View File

@ -111,8 +111,6 @@ export interface AttributeDecorator {
/** /**
* Type of the Attribute metadata. * Type of the Attribute metadata.
*
* @stable
*/ */
export interface Attribute { attributeName?: string; } export interface Attribute { attributeName?: string; }

View File

@ -0,0 +1,31 @@
/**
* @license
* Copyright 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 https://angular.io/license
*/
import {Injector, ReflectiveInjector} from '@angular/core';
export function main() {
describe('injector metadata examples', () => {
it('works', () => {
// #docregion Injector
const injector: Injector =
ReflectiveInjector.resolveAndCreate([{provide: 'validToken', useValue: 'Value'}]);
expect(injector.get('validToken')).toEqual('Value');
expect(() => injector.get('invalidToken')).toThrowError();
expect(injector.get('invalidToken', 'notFound')).toEqual('notFound');
// #enddocregion
});
it('injects injector', () => {
// #docregion injectInjector
const injector = ReflectiveInjector.resolveAndCreate([]);
expect(injector.get(Injector)).toBe(injector);
// #enddocregion
});
});
}

View File

@ -0,0 +1,176 @@
/**
* @license
* Copyright 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 https://angular.io/license
*/
import {Component, Directive, Host, Inject, Injectable, Optional, ReflectiveInjector, Self, SkipSelf} from '@angular/core';
import {TestBed} from '@angular/core/testing';
export function main() {
describe('di metadata examples', () => {
describe('Inject', () => {
it('works', () => {
// #docregion Inject
class Engine {}
@Injectable()
class Car {
constructor(@Inject('MyEngine') public engine: Engine) {}
}
const injector =
ReflectiveInjector.resolveAndCreate([{provide: 'MyEngine', useClass: Engine}, Car]);
expect(injector.get(Car).engine instanceof Engine).toBe(true);
// #enddocregion
});
it('works without decorator', () => {
// #docregion InjectWithoutDecorator
class Engine {}
@Injectable()
class Car {
constructor(public engine: Engine) {
} // same as constructor(@Inject(Engine) engine:Engine)
}
const injector = ReflectiveInjector.resolveAndCreate([Engine, Car]);
expect(injector.get(Car).engine instanceof Engine).toBe(true);
// #enddocregion
});
});
describe('Optional', () => {
it('works', () => {
// #docregion Optional
class Engine {}
@Injectable()
class Car {
constructor(@Optional() public engine: Engine) {}
}
const injector = ReflectiveInjector.resolveAndCreate([Car]);
expect(injector.get(Car).engine).toBeNull();
// #enddocregion
});
});
describe('Injectable', () => {
it('works', () => {
// #docregion Injectable
@Injectable()
class UsefulService {
}
@Injectable()
class NeedsService {
constructor(public service: UsefulService) {}
}
const injector = ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService]);
expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true);
// #enddocregion
});
it('throws without Injectable', () => {
// #docregion InjectableThrows
class UsefulService {}
class NeedsService {
constructor(public service: UsefulService) {}
}
expect(() => ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService])).toThrow();
// #enddocregion
});
});
describe('Self', () => {
it('works', () => {
// #docregion Self
class Dependency {}
@Injectable()
class NeedsDependency {
constructor(@Self() public dependency: Dependency) {}
}
let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
const nd = inj.get(NeedsDependency);
expect(nd.dependency instanceof Dependency).toBe(true);
inj = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = inj.resolveAndCreateChild([NeedsDependency]);
expect(() => child.get(NeedsDependency)).toThrowError();
// #enddocregion
});
});
describe('SkipSelf', () => {
it('works', () => {
// #docregion SkipSelf
class Dependency {}
@Injectable()
class NeedsDependency {
constructor(@SkipSelf() public dependency: Dependency) { this.dependency = dependency; }
}
const parent = ReflectiveInjector.resolveAndCreate([Dependency]);
const child = parent.resolveAndCreateChild([NeedsDependency]);
expect(child.get(NeedsDependency).dependency instanceof Dependency).toBe(true);
const inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
expect(() => inj.get(NeedsDependency)).toThrowError();
// #enddocregion
});
});
describe('Host', () => {
it('works', () => {
// #docregion Host
class OtherService {}
class HostService {}
@Directive({selector: 'child-directive'})
class ChildDirective {
constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
console.log('os is null', os);
console.log('hs is NOT null', hs);
}
}
@Component({
selector: 'parent-cmp',
providers: [HostService],
template: `
Dir: <child-directive></child-directive>
`
})
class ParentCmp {
}
@Component({
selector: 'app',
providers: [OtherService],
template: `Parent: <parent-cmp></parent-cmp>`
})
class App {
}
// #enddocregion
TestBed.configureTestingModule({
declarations: [App, ParentCmp, ChildDirective],
});
expect(() => TestBed.createComponent(App)).not.toThrow();
});
});
});
}

View File

@ -0,0 +1,149 @@
/**
* @license
* Copyright 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 https://angular.io/license
*/
import {Inject, Injectable, OpaqueToken, Optional, ReflectiveInjector, ValueProvider} from '@angular/core';
export function main() {
describe('Provider examples', () => {
describe('TypeProvider', () => {
it('works', () => {
// #docregion TypeProvider
@Injectable()
class Greeting {
salutation = 'Hello';
}
const injector = ReflectiveInjector.resolveAndCreate([
Greeting, // Shorthand for { provide: Greeting, useClass: Greeting }
]);
expect(injector.get(Greeting).salutation).toBe('Hello');
// #enddocregion
});
});
describe('ValueProvider', () => {
it('works', () => {
// #docregion ValueProvider
const injector =
ReflectiveInjector.resolveAndCreate([{provide: String, useValue: 'Hello'}]);
expect(injector.get(String)).toEqual('Hello');
// #enddocregion
});
});
describe('MultiProviderAspect', () => {
it('works', () => {
// #docregion MultiProviderAspect
const injector = ReflectiveInjector.resolveAndCreate([
{provide: 'local', multi: true, useValue: 'en'},
{provide: 'local', multi: true, useValue: 'sk'},
]);
const locales: string[] = injector.get('local');
expect(locales).toEqual(['en', 'sk']);
// #enddocregion
});
});
describe('ClassProvider', () => {
it('works', () => {
// #docregion ClassProvider
abstract class Shape { name: string; }
class Square extends Shape {
name = 'square';
}
const injector = ReflectiveInjector.resolveAndCreate([{provide: Shape, useClass: Square}]);
const shape: Shape = injector.get(Shape);
expect(shape.name).toEqual('square');
expect(shape instanceof Square).toBe(true);
// #enddocregion
});
it('is different then useExisting', () => {
// #docregion ClassProviderDifference
class Greeting {
salutation = 'Hello';
}
class FormalGreeting extends Greeting {
salutation = 'Greetings';
}
const injector = ReflectiveInjector.resolveAndCreate(
[FormalGreeting, {provide: Greeting, useClass: FormalGreeting}]);
// The injector returns different instances.
// See: {provide: ?, useExisting: ?} if you want the same instance.
expect(injector.get(FormalGreeting)).not.toBe(injector.get(Greeting));
// #enddocregion
});
});
describe('ExistingProvider', () => {
it('works', () => {
// #docregion ExistingProvider
class Greeting {
salutation = 'Hello';
}
class FormalGreeting extends Greeting {
salutation = 'Greetings';
}
const injector = ReflectiveInjector.resolveAndCreate(
[FormalGreeting, {provide: Greeting, useExisting: FormalGreeting}]);
expect(injector.get(Greeting).salutation).toEqual('Greetings');
expect(injector.get(FormalGreeting).salutation).toEqual('Greetings');
expect(injector.get(FormalGreeting)).toBe(injector.get(Greeting));
// #enddocregion
});
});
describe('FactoryProvider', () => {
it('works', () => {
// #docregion FactoryProvider
const Location = new OpaqueToken('location');
const Hash = new OpaqueToken('hash');
const injector = ReflectiveInjector.resolveAndCreate([
{provide: Location, useValue: 'http://angular.io/#someLocation'}, {
provide: Hash,
useFactory: (location: string) => location.split('#')[1],
deps: [Location]
}
]);
expect(injector.get(Hash)).toEqual('someLocation');
// #enddocregion
});
it('supports optional dependencies', () => {
// #docregion FactoryProviderOptionalDeps
const Location = new OpaqueToken('location');
const Hash = new OpaqueToken('hash');
const injector = ReflectiveInjector.resolveAndCreate([{
provide: Hash,
useFactory: (location: string) => `Hash for: ${location}`,
// use a nested array to define metadata for dependencies.
deps: [[new Optional(), new Inject(Location)]]
}]);
expect(injector.get(Hash)).toEqual('Hash for: null');
// #enddocregion
});
});
});
}