`,
+ providers:[HeroService]
+})
+
+export class Bio implements OnInit{
+
+ @Input() heroIndex:number;
+ private hero:Hero;
+
+ constructor(private _heroService:HeroService){
+ }
+
+ ngOnInit(){
+ this.hero = this._heroService.getHeroById(this.heroIndex);
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/contact-details.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/contact-details.component.ts
new file mode 100644
index 0000000000..d8f8331636
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/contact-details.component.ts
@@ -0,0 +1,23 @@
+// #docregion
+import {Component, Host, Optional, OnInit, ElementRef} from 'angular2/core';
+
+import {HeroService} from './hero.service';
+
+@Component({
+ selector:'contact-details',
+ template:'
Phone #: {{phoneNumber}}
'
+})
+
+export class ContactDetails implements OnInit{
+
+ private phoneNumber:string;
+ constructor(@Optional() @Host() private _heroService:HeroService, elementRef:ElementRef){
+ let nativeElement = elementRef.nativeElement;
+ }
+
+ ngOnInit(){
+ if(this._heroService){
+ this.phoneNumber = this._heroService.currentHero.phone;
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/date-logger.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/date-logger.service.ts
new file mode 100644
index 0000000000..73f76125b7
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/date-logger.service.ts
@@ -0,0 +1,9 @@
+// #docregion
+import {Injectable} from 'angular2/core';
+
+@Injectable()
+export class DateLoggerService{
+ logInfo(msg:string){
+ console.log(new Date().toString() + ` INFO: ${msg}`);
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero-bios.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero-bios.component.ts
new file mode 100644
index 0000000000..5953c00f7b
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero-bios.component.ts
@@ -0,0 +1,27 @@
+// #docregion
+import {Component} from 'angular2/core';
+import {Bio} from './bio.component';
+import {ContactDetails} from './contact-details.component';
+
+@Component({
+ template:`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`,
+ selector:'hero-bios',
+ directives:[Bio,ContactDetails]
+})
+
+export class Heroes{
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts
new file mode 100644
index 0000000000..5dde5baafb
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero-of-the-month.component.ts
@@ -0,0 +1,28 @@
+// #docregion
+import {Component,provide} from 'angular2/core';
+import {LoggerService} from './logger.service';
+import {Hero} from './hero';
+import {HeroService} from './hero.service';
+import {DateLoggerService} from './date-logger.service';
+import {RunnersUp} from './runners-up';
+import {runnersUpFactory} from './runners-up-provider.service';
+
+@Component({
+ selector:'hero-of-the-month',
+ template:`
Winner: {{_heroOfTheMonth.name}}
+
Reason for award: {{_heroOfTheMonth.description}}
+
Other candidates {{_runnersUp.names}}
`,
+
+ providers:[
+ HeroService,
+ provide(Hero, {useValue:new Hero('Magma','Had a great month!','555-555-5555')}),
+ provide(LoggerService, {useClass:DateLoggerService}),
+ provide(RunnersUp, {useFactory:runnersUpFactory, deps:[Hero, HeroService]})
+ ]
+})
+
+export class HeroOfTheMonth{
+ constructor(logger:LoggerService, private _heroOfTheMonth:Hero, private _runnersUp:RunnersUp){
+ logger.logInfo('starting up');
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero.service.ts
new file mode 100644
index 0000000000..a2ef71fb36
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero.service.ts
@@ -0,0 +1,27 @@
+// #docregion
+import {Hero} from './hero';
+import {Injectable} from 'angular2/core';
+
+@Injectable()
+export class HeroService{
+
+ currentHero:Hero;
+
+ //TODO move to database
+ private _heros:Array = [new Hero('RubberMan','Hero of many talents', '123-456-7899'),
+ new Hero('Magma','Hero of all trades', '555-555-5555'),
+ new Hero('Mr. Nice','The name says it all','111-222-3333')];
+
+ getHeroById(index:number):Hero{
+ if(!this.currentHero){
+ let heroes = this.getAllHeroes();
+ this.currentHero = heroes[index];
+ }
+
+ return this.currentHero;
+ }
+
+ getAllHeroes():Array{
+ return this._heros;
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/hero.ts b/public/docs/_examples/cb-dependency-injection/ts/app/hero.ts
new file mode 100644
index 0000000000..b4d8a71aeb
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/hero.ts
@@ -0,0 +1,5 @@
+// #docregion
+export class Hero{
+ constructor(public name:string, public description:string, public phone:string){
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/logger.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/logger.service.ts
new file mode 100644
index 0000000000..1f4608933a
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/logger.service.ts
@@ -0,0 +1,18 @@
+// #docregion
+import {Injectable} from 'angular2/core';
+
+@Injectable()
+export class LoggerService{
+
+ logInfo(msg:string){
+ console.log(`INFO: ${msg}`);
+ }
+
+ logDebug(msg:string){
+ console.log(`DEBUG: ${msg}`);
+ }
+
+ logError(msg:string){
+ console.log(`ERROR: ${msg}`);
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/main.ts b/public/docs/_examples/cb-dependency-injection/ts/app/main.ts
new file mode 100644
index 0000000000..73acc083e3
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/main.ts
@@ -0,0 +1,9 @@
+// #docregion
+import {bootstrap} from 'angular2/platform/browser';
+import {AppComponent} from './app.component';
+import {LoggerService} from './logger.service';
+import {UserContext} from './user-context.service';
+import {UserService} from './user.service';
+
+bootstrap(AppComponent, [LoggerService,UserService,UserContext])
+ .catch((err:any) => console.error(err));
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/runners-up-provider.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/runners-up-provider.service.ts
new file mode 100644
index 0000000000..84b4057a7d
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/runners-up-provider.service.ts
@@ -0,0 +1,12 @@
+// #docregion
+import {Hero} from './hero';
+import {HeroService} from './hero.service';
+import {RunnersUp} from './runners-up';
+
+export const runnersUpFactory = (winner:Hero, heroService:HeroService) => {
+ let names:string = heroService.getAllHeroes()
+ .filter((hero) => hero.name !== winner.name)
+ .map((hero) => hero.name).join(', ');
+
+ return new RunnersUp(names);
+};
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/runners-up.ts b/public/docs/_examples/cb-dependency-injection/ts/app/runners-up.ts
new file mode 100644
index 0000000000..b66a593402
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/runners-up.ts
@@ -0,0 +1,11 @@
+// #docregion
+import {Injectable} from 'angular2/core';
+
+@Injectable()
+export class RunnersUp{
+ names:string;
+
+ constructor(names:string){
+ this.names = names;
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes-base.ts b/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes-base.ts
new file mode 100644
index 0000000000..6ce4946b9b
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes-base.ts
@@ -0,0 +1,22 @@
+// #docregion
+import {HeroService} from './hero.service';
+import {Hero} from './hero';
+
+export class SortedHeroesBase{
+
+ sortedHeroes:Array;
+
+ constructor(private heroService:HeroService){
+ this.sortedHeroes = heroService.getAllHeroes();
+
+ this.sortedHeroes.sort((h1,h2) => {
+ if(h1.name < h2.name){
+ return -1;
+ }
+ if(h1.name > h2.name){
+ return 1
+ };
+ return 0;
+ });
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes.component.ts b/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes.component.ts
new file mode 100644
index 0000000000..22ac15389e
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/sorted-heroes.component.ts
@@ -0,0 +1,16 @@
+// #docregion
+import {Component} from 'angular2/core';
+import {SortedHeroesBase} from './sorted-heroes-base';
+import {HeroService} from './hero.service';
+
+@Component({
+ selector:'sorted-heroes',
+ template:`
{{hero.name}}
`,
+ providers:[HeroService]
+})
+
+export class SortedHeroes extends SortedHeroesBase{
+ constructor(heroService:HeroService){
+ super(heroService);
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/user-context.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/user-context.service.ts
new file mode 100644
index 0000000000..a0f6aabc51
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/user-context.service.ts
@@ -0,0 +1,24 @@
+// #docregion
+import {UserService} from './user.service';
+import {Injectable} from 'angular2/core';
+import {LoggerService} from './logger.service';
+
+@Injectable()
+export class UserContext{
+
+ name:string;
+ role:string;
+ loggedInSince:Date;
+
+ constructor(private _userService:UserService, private _loggerService:LoggerService){
+ this.loggedInSince = new Date();
+ }
+
+ loadUser(userId:number){
+ let user = this._userService.getUserById(userId);
+ this.name = user.name;
+ this.role = user.role;
+
+ this._loggerService.logDebug('loaded User');
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/app/user.service.ts b/public/docs/_examples/cb-dependency-injection/ts/app/user.service.ts
new file mode 100644
index 0000000000..01c941d326
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/app/user.service.ts
@@ -0,0 +1,10 @@
+// #docregion
+import {Injectable} from 'angular2/core';
+
+@Injectable()
+export class UserService{
+
+ getUserById(userId:number):any{
+ return {name:'Bombasto',role:'Admin'};
+ }
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/example-config.json b/public/docs/_examples/cb-dependency-injection/ts/example-config.json
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/cb-dependency-injection/ts/index.html b/public/docs/_examples/cb-dependency-injection/ts/index.html
new file mode 100644
index 0000000000..4e41644744
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/index.html
@@ -0,0 +1,39 @@
+
+
+
+
+ Dependency Injection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading app...
+
+
+
diff --git a/public/docs/_examples/cb-dependency-injection/ts/plnkr.json b/public/docs/_examples/cb-dependency-injection/ts/plnkr.json
new file mode 100644
index 0000000000..d20b01cf1d
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/plnkr.json
@@ -0,0 +1,9 @@
+{
+ "description": "Dependency Injection",
+ "files":[
+ "!**/*.d.ts",
+ "!**/*.js",
+ "!**/*.[1].*"
+ ],
+ "tags":["cookbook"]
+}
\ No newline at end of file
diff --git a/public/docs/_examples/cb-dependency-injection/ts/sample.css b/public/docs/_examples/cb-dependency-injection/ts/sample.css
new file mode 100644
index 0000000000..be3ca15c42
--- /dev/null
+++ b/public/docs/_examples/cb-dependency-injection/ts/sample.css
@@ -0,0 +1,5 @@
+.di-component{
+ padding: 10px;
+ width:300px;
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json
index 31e71596e4..04942d81f7 100644
--- a/public/docs/ts/latest/cookbook/_data.json
+++ b/public/docs/ts/latest/cookbook/_data.json
@@ -16,6 +16,11 @@
"description": "Share information between different directives and components"
},
+ "dependency-injection": {
+ "title": "Dependency Injection",
+ "description": "Using Dependency Injection"
+ },
+
"dynamic-form": {
"title": "Dynamic Form",
"description": "Render dynamic forms with NgFormModel"
diff --git a/public/docs/ts/latest/cookbook/dependency-injection.jade b/public/docs/ts/latest/cookbook/dependency-injection.jade
new file mode 100644
index 0000000000..5ccdca4574
--- /dev/null
+++ b/public/docs/ts/latest/cookbook/dependency-injection.jade
@@ -0,0 +1,143 @@
+include ../_util-fns
+
+:marked
+ Dependency Injection is a powerful pattern for managing code dependencies. In this cookbook we will explore many of the features of Dependency Injection (DI) in Angular.
+
+
+:marked
+ ## Table of contents
+
+ [Application Wide Dependency](#app-wide-dependency)
+
+ [Nested Dependencies](#nested-dependencies)
+
+ [DI and Inheritance](#di-inheritance)
+
+ [Component Level Dependencies](#component-level-depdendencies)
+
+ [Limit Dependency Lookup](#limit-dependency-lookup)
+
+ [Customizing DI](#customizing-di)
+
+ [Component Element](#component-element)
+
+:marked
+ **See the [live example](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)**.
+
+.l-main-section
+
+
+:marked
+ ## Application Wide Dependency
+ Dependencies registered using the `bootstrap` method are global dependencies and can be injected anywhere in the application.
+ In the following example we have created `LoggerService`, a global logger used to log application events.
+
++makeExample('cb-dependency-injection/ts/app/logger.service.ts','','logger.service.ts')
+
++makeExample('cb-dependency-injection/ts/app/main.ts','','main.ts')
+
+:marked
+ `LoggerService` is now registered with DI and can be injected into `AppComponent`.
+
++makeExample('cb-dependency-injection/ts/app/app.component.ts','','app.component.ts')
+
+
+:marked
+ ## DI and Inheritance
+ When inheriting a class with DI injected dependencies, all dependencies have to be injected in the sub class and passed down to the base class. Next we will show how to use DI in an inheritance chain. In our example we have created `SortedHeroes` and inherited `SortedHeroesBase` to display a sorted list of heroes.
+
++makeExample('cb-dependency-injection/ts/app/sorted-heroes.component.ts','','sorted-heroes.component.ts')
+
++makeExample('cb-dependency-injection/ts/app/sorted-heroes-base.ts','','sorted-heroes-base.ts')
+
+figure.image-display
+ img(src="/resources/images/cookbooks/dependency-injection/sorted-heroes.png" alt="Sorted Heroes")
+
+:marked
+ It may be surprising that we have to inject `HeroService` in `SortedHeroes` since it's really only used by `SortedHeroesBase`, but this is a key requirement of DI. If we move the responsibility of resolving `HeroService` to `SortedHeroesBase` we would lose control over our dependencies in `SortedHeroes` and negate many of the benefits of DI.
+
+
+:marked
+ ## Nested Dependencies
+ The benefits of DI become very clear when injecting dependencies with their own dependencies.
+ Previously we injected `UserContext` in `AppComponent`. `UserContext` has dependencies on both `LoggerService` and `UserService`, but the DI framework knows how to inject these depdendencies when instantiating `UserContext`. All we have to do is put the `@Injectable` decorator on the class to indicate that there are nested dependencies. `@Injectable()` is only required in cases where we have nested dependencies, but we are adding it to all our services for consistency.
+
+
++makeExample('cb-dependency-injection/ts/app/user-context.service.ts','','user-context.service.ts')
+
+:marked
+ We are using UserContext to show information about the current user and the final result looks like this:
+
+figure.image-display
+ img(src="/resources/images/cookbooks/dependency-injection/logged-in-user.png" alt="Logged In User")
+
+
+:marked
+ ## Component Level Dependencies
+ Application wide dependencies are instantiated once and all consumers share the same instance and state. However, we often need to store state at the component level. In the following example we will show how to register a service at the component level so that we can inject a different instance of the same service in each component instance.
+
+ We will be displaying a list of hero bios using `Heroes`.
+
++makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','','hero-bios.component.ts')
+
+:marked
+ `Heroes` contains a list of three instances of `Bio`, a simple component for displaying the bio for a given hero.
+
++makeExample('cb-dependency-injection/ts/app/bio.component.ts','','bio.component.ts')
+
+:marked
+ `Bio` uses `HeroService` to load the specific hero to display.
+
++makeExample('cb-dependency-injection/ts/app/hero.service.ts','','hero.service.ts')
+
+:marked
+ `HeroService` is caching the currently loaded hero, but each `Bio` instance needs to load a different hero. Clearly, a shared instance of `HeroService` will not work here. Instead we need to tell DI to give us a new instance of `HeroService` for each instance of `Bio` by registering `HersoService` in the `provider` array.
+
+figure.image-display
+ img(src="/resources/images/cookbooks/dependency-injection/hero-bios.png" alt="Bios")
+
+
+:marked
+ ## Limit Dependency Lookup
+ As we have seen, dependencies can be registered at any level in the component hierarchy. Anytime we request a dependency, Angular DI will walk up the injector tree until the first suitable provider is found somewhere in the chain. Most of the time this is the behavior we want, but there are times when we want to limit the lookup path. Angular DI provides the `@Host` decorator to make sure the dependency is resolved based on the provider defined in the host component.
+
+ `@Host` can be used in tandem with `@Optional` to ensure that dependencies don't resolve unless registered by the host specifically.
+
+ In our previoius sample we displayed hero bios where each instance of `Bio` required a separate instance of `HeroService`. We will now extend this sample by defining `ContactDetails` as a child component of `Bio`. Given this dependency it is important that `ContactDetails` uses the same instance of `HeroService` as its `Bio` host. We are adding `@Host` to ensure that.
+
++makeExample('cb-dependency-injection/ts/app/contact-details.component.ts','','contact-details.component.ts')
+
+
+:marked
+ ## Customizing DI
+ In the following sample we will show how to configure Angular's DI framework and control how instances are resolved.
+
+ A typical use case for wanting to customize DI is mocking. Mocks can be created for unit tests, but also to work ahead on a feature while we wait for other teams to build the services our components depend on. In the following example we will be building `HeroOfTheMonth` where we customize the behavior of some of the services we introduced in previous sections.
+
++makeExample('cb-dependency-injection/ts/app/hero-of-the-month.component.ts','','hero-of-the-month.component.ts')
+
+:marked
+ ***useValue***
+
+ We are using `useValue` to always return a specific hero whenever a `Hero` is injected.
+
+ ***useClass***
+
+ Previsoulsy we created `LoggerService`, but we are experimenting with a new logger, so in `HeroOfTheMonth` we want to use `useClass` to return an instance of `DateLoggerService` whenever a `LoggerService` is requested.
+
+ ***useFactory***
+
+ Along side the lucky hero of the month we also want to recognize the runners-up for the month. We are injecting a `RunnersUp` object with a list of heroes who came close to winning the prestigious award. This list needs to be created based on some internal logic, so we have used `useFactory` to create a factory to create the list.
+
++makeExample('cb-dependency-injection/ts/app/runners-up-provider.service.ts','','runners-up-provider.service.ts')
+
++makeExample('cb-dependency-injection/ts/app/runners-up.ts','','runners-up.ts')
+
+figure.image-display
+ img(src="/resources/images/cookbooks/dependency-injection/hero-of-month.png" alt="Hero of the month")
+
+
+:marked
+ ## Component Element
+
+ On occasion we might need to access a component's underlying host element. Direct DOM access should generally be avoided, but looking back at our `ContactDetails` sample, we are using DI to inject `ElementRef` to get access to the underlying component element.
\ No newline at end of file
diff --git a/public/resources/images/cookbooks/dependency-injection/hero-bios.png b/public/resources/images/cookbooks/dependency-injection/hero-bios.png
new file mode 100644
index 0000000000..611e61261b
Binary files /dev/null and b/public/resources/images/cookbooks/dependency-injection/hero-bios.png differ
diff --git a/public/resources/images/cookbooks/dependency-injection/hero-of-month.png b/public/resources/images/cookbooks/dependency-injection/hero-of-month.png
new file mode 100644
index 0000000000..84067037a0
Binary files /dev/null and b/public/resources/images/cookbooks/dependency-injection/hero-of-month.png differ
diff --git a/public/resources/images/cookbooks/dependency-injection/logged-in-user.png b/public/resources/images/cookbooks/dependency-injection/logged-in-user.png
new file mode 100644
index 0000000000..4a43da33c9
Binary files /dev/null and b/public/resources/images/cookbooks/dependency-injection/logged-in-user.png differ
diff --git a/public/resources/images/cookbooks/dependency-injection/sorted-heroes.png b/public/resources/images/cookbooks/dependency-injection/sorted-heroes.png
new file mode 100644
index 0000000000..6adfeae498
Binary files /dev/null and b/public/resources/images/cookbooks/dependency-injection/sorted-heroes.png differ