docs(di): update docs on di
This commit is contained in:
parent
d299ce4bcf
commit
0a2132ef10
|
@ -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
|
||||
*/
|
||||
export abstract class Injector {
|
||||
|
@ -34,22 +51,6 @@ export abstract class Injector {
|
|||
* - Throws {@link NoProviderError} if no `notFoundValue` that is not equal to
|
||||
* Injector.THROW_IF_NOT_FOUND is given
|
||||
* - 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(); }
|
||||
|
|
|
@ -16,45 +16,29 @@ import {makeParamDecorator} from '../util/decorators';
|
|||
*/
|
||||
export interface InjectDecorator {
|
||||
/**
|
||||
* A parameter metadata that specifies a dependency.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/6uHYJK?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
*
|
||||
* @whatItDoes A parameter decorator that specifies a dependency.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* engine;
|
||||
* constructor(@Inject("MyEngine") engine:Engine) {
|
||||
* this.engine = engine;
|
||||
* }
|
||||
* constructor(@Inject("MyEngine") public 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
|
||||
* parameter.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
* {@example core/di/ts/metadata_spec.ts region='InjectWithoutDecorator'}
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
(token: any): any;
|
||||
|
@ -84,25 +68,23 @@ export const Inject: InjectDecorator = makeParamDecorator('Inject', [['token', u
|
|||
*/
|
||||
export interface OptionalDecorator {
|
||||
/**
|
||||
* A parameter metadata that marks a dependency as optional. {@link Injector} provides `null` if
|
||||
* the dependency is not found.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/AsryOm?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* class Engine {}
|
||||
*
|
||||
* @whatItDoes A parameter metadata that marks a dependency as optional.
|
||||
* {@link Injector} provides `null` if the dependency is not found.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* engine;
|
||||
* constructor(@Optional() engine:Engine) {
|
||||
* this.engine = engine;
|
||||
* }
|
||||
* constructor(@Optional() public 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
|
||||
*/
|
||||
(): any;
|
||||
|
@ -131,35 +113,25 @@ export const Optional: OptionalDecorator = makeParamDecorator('Optional', []);
|
|||
*/
|
||||
export interface InjectableDecorator {
|
||||
/**
|
||||
* A marker metadata that marks a class as available to {@link Injector} for creation.
|
||||
*
|
||||
* ### 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);
|
||||
* @whatItDoes A marker metadata that marks a class as available to {@link Injector} for creation.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @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
|
||||
* does not have `@Injectable` marker, as shown in the example below.
|
||||
*
|
||||
* ```typescript
|
||||
* class UsefulService {}
|
||||
* {@example core/di/ts/metadata_spec.ts region='InjectableThrows'}
|
||||
*
|
||||
* class NeedsService {
|
||||
* constructor(public service:UsefulService) {}
|
||||
* }
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([NeedsService, UsefulService]);
|
||||
* expect(() => injector.get(NeedsService)).toThrowError();
|
||||
* ```
|
||||
* @stable
|
||||
*/
|
||||
(): any;
|
||||
|
@ -188,31 +160,22 @@ export const Injectable: InjectableDecorator = makeParamDecorator('Injectable',
|
|||
*/
|
||||
export interface SelfDecorator {
|
||||
/**
|
||||
* Specifies that an {@link Injector} should retrieve a dependency only from itself.
|
||||
*
|
||||
* ### 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();
|
||||
* @whatItDoes Specifies that an {@link Injector} should retrieve a dependency only from itself.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @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
|
||||
*/
|
||||
(): any;
|
||||
|
@ -242,29 +205,22 @@ export const Self: SelfDecorator = makeParamDecorator('Self', []);
|
|||
*/
|
||||
export interface SkipSelfDecorator {
|
||||
/**
|
||||
* Specifies that the dependency resolution should start from the parent injector.
|
||||
*
|
||||
* ### 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();
|
||||
* @whatItDoes Specifies that the dependency resolution should start from the parent injector.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @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
|
||||
*/
|
||||
(): any;
|
||||
|
@ -293,56 +249,24 @@ export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf', []);
|
|||
*/
|
||||
export interface HostDecorator {
|
||||
/**
|
||||
* Specifies that an injector should retrieve a dependency from any injector until reaching the
|
||||
* closest host.
|
||||
*
|
||||
* In Angular, a component element is automatically declared as a host for all the injectors in
|
||||
* its view.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/GX79pV?p=preview))
|
||||
*
|
||||
* 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);
|
||||
* }
|
||||
* @whatItDoes Specifies that an injector should retrieve a dependency from any injector until
|
||||
* reaching the
|
||||
* host element of the current component.
|
||||
* @howToUse
|
||||
* ```
|
||||
* @Injectable()
|
||||
* class Car {
|
||||
* constructor(@Host() public engine:Engine) {}
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'parent-cmp',
|
||||
* providers: [HostService],
|
||||
* template: `
|
||||
* Dir: <child-directive></child-directive>
|
||||
* `,
|
||||
* directives: [ChildDirective]
|
||||
* })
|
||||
* class ParentCmp {
|
||||
* }
|
||||
* @description
|
||||
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* {@example core/di/ts/metadata_spec.ts region='Host'}
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'app',
|
||||
* providers: [OtherService],
|
||||
* template: `
|
||||
* Parent: <parent-cmp></parent-cmp>
|
||||
* `,
|
||||
* directives: [ParentCmp]
|
||||
* })
|
||||
* class App {
|
||||
* }
|
||||
*```
|
||||
* @stable
|
||||
*/
|
||||
(): any;
|
||||
|
|
|
@ -9,50 +9,45 @@
|
|||
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.
|
||||
* This form is a short form of `TypeProvider`;
|
||||
*
|
||||
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* @Injectable()
|
||||
* class Greeting {
|
||||
* text: 'Hello';
|
||||
* }
|
||||
*
|
||||
* @Injectable()
|
||||
* 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');
|
||||
* ```
|
||||
* {@example core/di/ts/provider_spec.ts region='TypeProvider'}
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
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
|
||||
* ```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
|
||||
*/
|
||||
export interface ValueProvider {
|
||||
|
@ -71,62 +66,31 @@ export interface ValueProvider {
|
|||
* providers spread across many files to provide configuration information to a common token.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* var locale = new OpaqueToken('local');
|
||||
*
|
||||
* const injector = Injector.resolveAndCreate([
|
||||
* { provide: locale, multi: true, useValue: 'en' },
|
||||
* { provide: locale, multi: true, useValue: 'sk' },
|
||||
* ]);
|
||||
*
|
||||
* const locales: string[] = injector.get(locale);
|
||||
* expect(locales).toEqual(['en', 'sk']);
|
||||
* ```
|
||||
* {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
|
||||
*/
|
||||
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
|
||||
* ```javascript
|
||||
* abstract class Shape {
|
||||
* name: string;
|
||||
* }
|
||||
*
|
||||
* class Square extends Shape {
|
||||
* name = 'square';
|
||||
* }
|
||||
* {@example core/di/ts/provider_spec.ts region='ClassProvider'}
|
||||
*
|
||||
* const injector = Injector.resolveAndCreate([
|
||||
* {provide: Shape, useClass: Square}
|
||||
* ]);
|
||||
*
|
||||
* 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));
|
||||
* ```
|
||||
* Note that following two providers are not equal:
|
||||
* {@example core/di/ts/provider_spec.ts region='ClassProviderDifference'}
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
|
@ -146,56 +110,26 @@ export interface ClassProvider {
|
|||
* providers spread across many files to provide configuration information to a common token.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* abstract class Locale {
|
||||
* name: string;
|
||||
* };
|
||||
*
|
||||
* @Injectable()
|
||||
* 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']);
|
||||
* ```
|
||||
* {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
|
||||
*/
|
||||
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
|
||||
* ```javascript
|
||||
* class Greeting {
|
||||
* salutation = 'Hello';
|
||||
* }
|
||||
*
|
||||
* class FormalGreeting extends Greeting {
|
||||
* salutation = 'Greetings';
|
||||
* }
|
||||
* {@example core/di/ts/provider_spec.ts region='ExistingProvider'}
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
export interface ExistingProvider {
|
||||
|
@ -214,52 +148,32 @@ export interface ExistingProvider {
|
|||
* providers spread across many files to provide configuration information to a common token.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* abstract class Locale {
|
||||
* name: string;
|
||||
* };
|
||||
*
|
||||
* @Injectable()
|
||||
* 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']);
|
||||
* ```
|
||||
* {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
|
||||
*/
|
||||
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
|
||||
* ```javascript
|
||||
* const HASH = new OpaqueToken('hash');
|
||||
*
|
||||
* const injector = Injector.resolveAndCreate([
|
||||
* {provide: Location, useValue: window.location},
|
||||
* {provide: HASH, useFactory: (location: Location) => location.hash, deps: [Location]}
|
||||
* ]);
|
||||
* {@example core/di/ts/provider_spec.ts region='FactoryProvider'}
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
export interface FactoryProvider {
|
||||
|
@ -285,65 +199,21 @@ export interface FactoryProvider {
|
|||
* providers spread across many files to provide configuration information to a common token.
|
||||
*
|
||||
* ### Example
|
||||
* ```javascript
|
||||
* class Locale {
|
||||
* constructor(public name: string) {}
|
||||
* };
|
||||
* const PRIMARY = new OpequeToken('primary');
|
||||
* const SECONDARY = new OpequeToken('secondary');
|
||||
*
|
||||
* const injector = Injector.resolveAndCreate([
|
||||
* { 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']);
|
||||
* ```
|
||||
* {@example core/di/ts/provider_spec.ts region='MultiProviderAspect'}
|
||||
*/
|
||||
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},
|
||||
* {@link FactoryProvider}.
|
||||
*
|
||||
* ```javascript
|
||||
* class Greeting {
|
||||
* salutation = 'Hello';
|
||||
* }
|
||||
* @description
|
||||
* For more details, see the {@linkDocs guide/dependency-injection "Dependency Injection Guide"}.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
export type Provider =
|
||||
|
|
|
@ -111,8 +111,6 @@ export interface AttributeDecorator {
|
|||
|
||||
/**
|
||||
* Type of the Attribute metadata.
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export interface Attribute { attributeName?: string; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
|
@ -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
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue