diff --git a/modules/@angular/core/src/di/injector.ts b/modules/@angular/core/src/di/injector.ts
index 6e86524f15..3c9a750092 100644
--- a/modules/@angular/core/src/di/injector.ts
+++ b/modules/@angular/core/src/di/injector.ts
@@ -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(); }
diff --git a/modules/@angular/core/src/di/metadata.ts b/modules/@angular/core/src/di/metadata.ts
index f5a759fd7c..8dff4459e2 100644
--- a/modules/@angular/core/src/di/metadata.ts
+++ b/modules/@angular/core/src/di/metadata.ts
@@ -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:
- * `,
- * 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:
- * `,
- * directives: [ParentCmp]
- * })
- * class App {
- * }
- *```
* @stable
*/
(): any;
diff --git a/modules/@angular/core/src/di/provider.ts b/modules/@angular/core/src/di/provider.ts
index 6c266028ae..d22c829f4f 100644
--- a/modules/@angular/core/src/di/provider.ts
+++ b/modules/@angular/core/src/di/provider.ts
@@ -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 {}
/**
- * 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 =
diff --git a/modules/@angular/core/src/metadata/di.ts b/modules/@angular/core/src/metadata/di.ts
index b6dee1ab50..63c2ff6eb1 100644
--- a/modules/@angular/core/src/metadata/di.ts
+++ b/modules/@angular/core/src/metadata/di.ts
@@ -111,8 +111,6 @@ export interface AttributeDecorator {
/**
* Type of the Attribute metadata.
- *
- * @stable
*/
export interface Attribute { attributeName?: string; }
diff --git a/modules/@angular/examples/core/di/ts/injector_spec.ts b/modules/@angular/examples/core/di/ts/injector_spec.ts
new file mode 100644
index 0000000000..9b0a327705
--- /dev/null
+++ b/modules/@angular/examples/core/di/ts/injector_spec.ts
@@ -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
+
+ });
+ });
+}
diff --git a/modules/@angular/examples/core/di/ts/metadata_spec.ts b/modules/@angular/examples/core/di/ts/metadata_spec.ts
new file mode 100644
index 0000000000..1182676a4e
--- /dev/null
+++ b/modules/@angular/examples/core/di/ts/metadata_spec.ts
@@ -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:
+ `
+ })
+ class ParentCmp {
+ }
+
+ @Component({
+ selector: 'app',
+ providers: [OtherService],
+ template: `Parent: `
+ })
+ class App {
+ }
+ // #enddocregion
+
+ TestBed.configureTestingModule({
+ declarations: [App, ParentCmp, ChildDirective],
+ });
+ expect(() => TestBed.createComponent(App)).not.toThrow();
+ });
+ });
+
+ });
+}
diff --git a/modules/@angular/examples/core/di/ts/provider_spec.ts b/modules/@angular/examples/core/di/ts/provider_spec.ts
new file mode 100644
index 0000000000..31d2c4c739
--- /dev/null
+++ b/modules/@angular/examples/core/di/ts/provider_spec.ts
@@ -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
+ });
+ });
+
+ });
+}