Professional Documents
Culture Documents
Injection ts COOKBOOK
DEPENDENCY INJECTION
Table of contents
Application-wide dependencies
class-interface
OpaqueToken
Application-wide dependencies
Register providers for dependencies used throughout the application in the root
application component, AppComponent .
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 2/47
11/20/2016 Dependency Injection ts COOKBOOK
app/app.component.ts (excerpt)
@Component({
moduleId: module.id,
selector: 'my-app',
templateUrl: 'app.component.html',
providers: [ LoggerService, UserContextService, UserService ]
})
export class AppComponent {
/* . . . */
}
All of these services are implemented as classes. Service classes can act as their
own providers which is why listing them in the providers array is all the
registration we need.
Now that we've registered these services, Angular can inject them into the
constructor of any component or service, anywhere in the application.
constructor(logger: LoggerService) {
logger.logInfo('Creating HeroBiosComponent');
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 3/47
11/20/2016 Dependency Injection ts COOKBOOK
We see an example of the second case here, where we con嘀gure the Component
Router with a non-default location strategy by listing its provider in the providers
list of the AppModule .
app/app.module.ts (providers)
providers: [
{ provide: LocationStrategy, useClass: HashLocationStrategy }
]
The consumer of an injected service does not know how to create that service. It
shouldn't care. It's the dependency injection's job to create and cache that service.
Sometimes a service depends on other services ... which may depend on yet other
services. Resolving these nested dependencies in the correct order is also the
framework's job. At each step, the consumer of dependencies simply declares what
it requires in its constructor and the framework takes over.
For example, we inject both the LoggerService and the UserContext in the
AppComponent .
app/app.component.ts
user-context.service.ts (injection)
@Injectable()
export class UserContextService {
constructor(private userService: UserService, private
loggerService: LoggerService) {
}
}
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 5/47
11/20/2016 Dependency Injection ts COOKBOOK
which the framework already has, and the UserService , which it has yet to create.
The UserService has no dependencies so the dependency injection framework
can just new one into existence.
The beauty of dependency injection is that the author of AppComponent didn't care
about any of this. The author simply declared what was needed in the constructor
( LoggerService and UserContextService ) and the framework did the rest.
Once all the dependencies are in place, the AppComponent displays the user
information:
@Injectable()
Notice the @Injectable() decorator on the UserContextService class.
user-context.service.ts (@Injectable)
@Injectable()
export class UserContextService {
}
That decorator makes it possible for Angular to identify the types of its two
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 6/47
11/20/2016 Dependency Injection ts COOKBOOK
Technically, the @Injectable() decorator is only required for a service class that
has its own dependencies. The LoggerService doesn't depend on anything. The
logger would work if we omitted @Injectable() and the generated code would be
slightly smaller.
But the service would break the moment we gave it a dependency and we'd have to
go back and and add @Injectable() to 嘀x it. We add @Injectable() from the
start for the sake of consistency and to avoid future pain.
(and created) at any component level and multiple times if provided in multiple
components.
We can limit the scope of an injected service to a branch of the application hierarchy
by providing that service at the sub-root component for that branch. Here we provide
the HeroService to the HeroesBaseComponent by listing it in the providers
array:
1. @Component({
2. selector: 'unsorted-heroes',
3. template: `<div *ngFor="let hero of heroes">{{hero.name}}</div>`,
4. providers: [HeroService]
5. })
6. export class HeroesBaseComponent implements OnInit {
7. constructor(private heroService: HeroService) { }
8. }
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 8/47
11/20/2016 Dependency Injection ts COOKBOOK
heroes.
Take a break!
This much Dependency Injection knowledge may be all that many Angular
developers ever need to build their applications. It doesn't always have to be
more complicated.
A good example is a service that holds state for its companion component instance.
We need a separate instance of the service for each component. Each service has
its own work-state, isolated from the service-and-state of a different component. We
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 9/47
11/20/2016 Dependency Injection ts COOKBOOK
call this sandboxing because each service and component instance has its own
sandbox to play in.
ap/hero-bios.component.ts
1. @Component({
2. selector: 'hero-bios',
3. template: `
4. <hero-bio [heroId]="1"></hero-bio>
5. <hero-bio [heroId]="2"></hero-bio>
6. <hero-bio [heroId]="3"></hero-bio>`,
7. providers: [HeroService]
8. })
9. export class HeroBiosComponent {
10. }
app/hero-cache.service.ts
1. @Injectable()
2. export class HeroCacheService {
3. hero: Hero;
4. constructor(private heroService: HeroService) {}
5.
6. fetchCachedHero(id: number) {
7. if (!this.hero) {
8. this.hero = this.heroService.getHeroById(id);
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 10/47
11/20/2016 Dependency Injection ts COOKBOOK
9. }
10. return this.hero;
11. }
12. }
Clearly the three instances of the HeroBioComponent can't share the same
HeroCacheService . They'd be competing with each other to determine which hero
to cache.
app/hero-bio.component.ts
1. @Component({
2. selector: 'hero-bio',
3. template: `
4. <h4>{{hero.name}}</h4>
5. <ng-content></ng-content>
6. <textarea cols="25" [(ngModel)]="hero.description">
</textarea>`,
7. providers: [HeroCacheService]
8. })
9.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 11/47
11/20/2016 Dependency Injection ts COOKBOOK
Find this example in live code and con嘀rm that the three HeroBioComponent
instances have their own cached hero data.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 12/47
11/20/2016 Dependency Injection ts COOKBOOK
We want this behavior most of the time. But sometimes we need to limit the search
and/or accommodate a missing dependency. We can modify Angular's search
behavior with the @Host and @Optional qualifying decorators, used individually
or together.
The @Optional decorator tells Angular to continue when it can't 嘀nd the
dependency. Angular sets the injection parameter to null instead.
The @Host decorator stops the upward search at the host component.
The host component is typically the component requesting the dependency. But
when this component is projected into a parent component, that parent component
becomes the host. We look at this second, more interesting case in our next
example.
Demonstration
The HeroBiosAndContactsComponent is a revision of the HeroBiosComponent
that we looked at above.
app/hero-bios.component.ts (HeroBiosAndContactsComponent)
1. @Component({
2. selector: 'hero-bios-and-contacts',
3. template: `
4. <hero-bio [heroId]="1"> <hero-contact></hero-contact> </hero-
bio>
5. <hero-bio [heroId]="2"> <hero-contact></hero-contact> </hero-
bio>
6. <hero-bio [heroId]="3"> <hero-contact></hero-contact> </hero-
bio>`,
7. providers: [HeroService]
8. })
9. export class HeroBiosAndContactsComponent {
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 13/47
11/20/2016 Dependency Injection ts COOKBOOK
template: `
<hero-bio [heroId]="1"> <hero-contact></hero-contact> </hero-
bio>
<hero-bio [heroId]="2"> <hero-contact></hero-contact> </hero-
bio>
<hero-bio [heroId]="3"> <hero-contact></hero-contact> </hero-
bio>`,
HeroBioComponent template:
app/hero-bio.component.ts (template)
template: `
<h4>{{hero.name}}</h4>
<ng-content></ng-content>
<textarea cols="25" [(ngModel)]="hero.description"></textarea>`,
It looks like this, with the hero's telephone number from HeroContactComponent
projected above the hero description:
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 14/47
11/20/2016 Dependency Injection ts COOKBOOK
app/hero-contact.component.ts
1. @Component({
2. selector: 'hero-contact',
3. template: `
4. <div>Phone #: {{phoneNumber}}
5. <span *ngIf="hasLogger">!!!</span></div>`
6. })
7. export class HeroContactComponent {
8.
9. hasLogger = false;
10.
11. constructor(
12. @Host() // limit to the host component's instance of the
HeroCacheService
13. private heroCache: HeroCacheService,
14.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 15/47
11/20/2016 Dependency Injection ts COOKBOOK
27. }
app/hero-contact.component.ts
The @Host() function decorating the heroCache property ensures that we get a
reference to the cache service from the parent HeroBioComponent . Angular
throws if the parent lacks that service, even if a component higher in the component
tree happens to have that service.
Angular would throw an error if we hadn't also decorated the property with the
@Optional() function. Thanks to @Optional() , Angular sets the
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 16/47
11/20/2016 Dependency Injection ts COOKBOOK
If we comment out the @Host() decorator, Angular now walks up the injector
ancestor tree until it 嘀nds the logger at the AppComponent level. The logger logic
kicks in and the hero display updates with the gratuitous "!!!", indicating that the
logger was found.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 17/47
11/20/2016 Dependency Injection ts COOKBOOK
On the other hand, if we restore the @Host() decorator and comment out
@Optional , the application fails for lack of the required logger at the host
component level.
EXCEPTION: No provider for LoggerService! (HeroContactComponent -
> LoggerService)
app/highlight.directive.ts
3. @Directive({
4. selector: '[myHighlight]'
5. })
6. export class HighlightDirective {
7.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 18/47
11/20/2016 Dependency Injection ts COOKBOOK
The directive sets the background to a highlight color when the user mouses over
the DOM element to which it is applied.
The sample code applies the directive's myHighlight attribute to two <div> tags,
嘀rst without a value (yielding the default color) and then with an assigned color
value.
app/app.component.html (highlight)
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 19/47
11/20/2016 Dependency Injection ts COOKBOOK
The following image shows the effect of mousing over the <hero-bios-and-
contacts> tag.
Background
We get a service from a dependency injector by giving it a token.
constructor(logger: LoggerService) {
logger.logInfo('Creating HeroBiosComponent');
}
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 20/47
11/20/2016 Dependency Injection ts COOKBOOK
Angular asks the injector for the service associated with the LoggerService and
and assigns the returned value to the logger parameter.
Where did the injector get that value? It may already have that value in its internal
container. If it doesn't, it may be able to make one with the help of a provider. A
provider is a recipe for delivering a service associated with a token.
If the injector doesn't have a provider for the requested token, it delegates
the request to its parent injector, where the process repeats until there are
no more injectors. If the search is futile, the injector throws an error ...
unless the request was optional.
A new injector has no providers. Angular initializes the injectors it creates with some
providers it cares about. We have to register our own application providers manually,
usually in the providers array of the Component or Directive metadata:
app/app.component.ts (providers)
De嘀ning providers
The simple class provider is the most typical by far. We mention the class in the
providers array and we're done.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 21/47
11/20/2016 Dependency Injection ts COOKBOOK
providers: [HeroService]
It's that simple because the most common injected service is an instance of a class.
But not every dependency can be satis嘀ed by creating a new instance of a class. We
need other ways to deliver dependency values and that means we need other ways
to specify a provider.
It's visually simple: a few properties and the output of a logger. The code behind it
gives us plenty to talk about.
hero-of-the-month.component.ts
3. import { DateLoggerService,
4. MinimalLogger } from './date-logger.service';
5. import { Hero } from './hero';
6. import { HeroService } from './hero.service';
7. import { LoggerService } from './logger.service';
8. import { RUNNERS_UP,
9. runnersUpFactory } from './runners-up';
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 22/47
11/20/2016 Dependency Injection ts COOKBOOK
10.
11. @Component({
12. selector: 'hero-of-the-month',
13. template: template,
14. providers: [
15. { provide: Hero, useValue: someHero },
16. { provide: TITLE, useValue: 'Hero of the Month' },
17. { provide: HeroService, useClass: HeroService },
18. { provide: LoggerService, useClass: DateLoggerService },
19. { provide: MinimalLogger, useExisting: LoggerService },
20. { provide: RUNNERS_UP, useFactory: runnersUpFactory(2),
deps: [Hero, HeroService] }
21. ]
22. })
23. export class HeroOfTheMonthComponent {
24. logs: string[] = [];
25.
26. constructor(
27. logger: MinimalLogger,
28. public heroOfTheMonth: Hero,
29. @Inject(RUNNERS_UP) public runnersUp: string,
30. @Inject(TITLE) public title: string)
31. {
32. this.logs = logger.logs;
33. logger.logInfo('starting up');
34. }
35. }
The provide object literal takes a token and a de嘀nition object. The token is
usually a class but it doesn't have to be.
The de嘀nition object has one main property, (e.g. useValue ) that indicates how the
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 23/47
11/20/2016 Dependency Injection ts COOKBOOK
Set the useValue property to a 嘀xed value that the provider can return as the
dependency object.
Use this technique to provide runtime con嘀guration constants such as web-site base
addresses and feature 쀀ags. We often use a value provider in a unit test to replace a
production service with a fake or mock.
The Hero provider token is a class which makes sense because the value is a
Hero and the consumer of the injected hero would want the type information.
The TITLE provider token is not a class. It's a special kind of provider lookup key
called an OpaqueToken. We often use an OpaqueToken when the dependency is a
simple value like a string, a number, or a function.
The value of a value provider must be de嘀ned now. We can't create the value later.
Obviously the title string literal is immediately available. The someHero variable in
this example was set earlier in the 嘀le:
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 24/47
11/20/2016 Dependency Injection ts COOKBOOK
555-5555');
The other providers create their values lazily when they're needed for injection.
The useClass provider creates and returns new instance of the speci嘀ed class.
The 嘀rst provider is the de-sugared, expanded form of the most typical case in which
the class to be created ( HeroService ) is also the provider's injection token. We
wrote it in this long form to de-mystify the preferred short form.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 25/47
11/20/2016 Dependency Injection ts COOKBOOK
app/date-logger.service.ts
@Injectable()
export class DateLoggerService extends LoggerService implements
MinimalLogger
{
logInfo(msg: any) { super.logInfo(stamp(msg)); }
logDebug(msg: any) { super.logInfo(stamp(msg)); }
logError(msg: any) { super.logError(stamp(msg)); }
}
The useExisting provider maps one token to another. In effect, the 嘀rst token is
an alias for the service associated with second token, creating two ways to access
the same service object.
Narrowing an API through an aliasing interface is one important use case for this
technique. We're aliasing for that very purpose here. Imagine that the
LoggerService had a large API (it's actually only three methods and a property).
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 26/47
11/20/2016 Dependency Injection ts COOKBOOK
We want to shrink that API surface to just the two members exposed by the
MinimalLogger class-interface:
app/date-logger.service.ts (MinimalLogger)
Angular actually sets the logger parameter to the injector's full version of the
LoggerService which happens to be the DateLoggerService thanks to the
override provider registered previously via useClass . The following image, which
displays the logging date, con嘀rms the point:
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 27/47
11/20/2016 Dependency Injection ts COOKBOOK
Use this technique to create a dependency object with a factory function whose
inputs are some combination of injected services and local state.
The local state is the number 2 , the number of runners-up this component should
show. We execute runnersUpFactory immediately with 2 .
The runnersUpFactory itself isn't the provider factory function. The true provider
factory function is the function that runnersUpFactory returns.
runners-up.ts (excerpt)
Angular supplies these arguments from injected values identi嘀ed by the two tokens
in the deps array. The two deps values are tokens that the injector uses to provide
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 28/47
11/20/2016 Dependency Injection ts COOKBOOK
After some undisclosed work, the function returns the string of names and Angular
injects it into the runnersUp parameter of the HeroOfTheMonthComponent .
But the token doesn't have to be a class and even when it is a class, it doesn't have
to be the same type as the returned object. That's the subject of our next section.
class-interface
In the previous Hero of the Month example, we used the MinimalLogger class as
the token for a provider of a LoggerService .
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 29/47
11/20/2016 Dependency Injection ts COOKBOOK
We usually inherit from an abstract class. But LoggerService doesn't inherit from
MinimalLogger . No class inherits from it. Instead, we use it like an interface.
We call a class used in this way a class-interface. The key bene嘀t of a class-interface
is that we can get the strong-typing of an interface and we can use it as a provider
token in the same manner as a normal class.
A class-interface should de嘀ne only the members that its consumers are allowed to
call. Such a narrowing interface helps decouple the concrete class from its
consumers. The MinimalLogger de嘀nes just two of the LoggerClass members.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 30/47
11/20/2016 Dependency Injection ts COOKBOOK
The minimize memory cost, the class should have no implementation. The
MinimalLogger transpiles to this unoptimized, pre-mini嘀ed JavaScript:
OpaqueToken
Dependency objects can be simple values like dates, numbers and strings or
shapeless objects like arrays and functions.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 31/47
11/20/2016 Dependency Injection ts COOKBOOK
Such objects don't have application interfaces and therefore aren't well represented
by a class. They're better represented by a token that is both unique and symbolic, a
JavaScript object that has a friendly name but won't con쀀ict with another token that
happens to have the same name.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 32/47
11/20/2016 Dependency Injection ts COOKBOOK
The HeroesBaseComponent could stand on its own. It demands its own instance
of the HeroService to get heroes and displays them in the order they arrive from
the database.
app/sorted-heroes.component.ts (HeroesBaseComponent)
1. @Component({
2. selector: 'unsorted-heroes',
3. template: `<div *ngFor="let hero of heroes">{{hero.name}}</div>`,
4. providers: [HeroService]
5. })
6. export class HeroesBaseComponent implements OnInit {
7. constructor(private heroService: HeroService) { }
8.
9. heroes: Array<Hero>;
10.
11. ngOnInit() {
12. this.heroes = this.heroService.getAllHeroes();
13. this.afterGetHeroes();
14. }
15.
19. }
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 33/47
11/20/2016 Dependency Injection ts COOKBOOK
Users want to see the heroes in alphabetical order. Rather than modify the original
component, we sub-class it and create a SortedHeroesComponent that sorts the
heroes before presenting them. The SortedHeroesComponent lets the base class
fetch the heroes. (we said it was contrived).
Unfortunately, Angular cannot inject the HeroService directly into the base class.
We must provide the HeroService again for this component, then pass it down to
the base class inside the constructor.
app/sorted-heroes.component.ts (SortedHeroesComponent)
1. @Component({
2. selector: 'sorted-heroes',
3. template: `<div *ngFor="let hero of heroes">{{hero.name}}</div>`,
4. providers: [HeroService]
5. })
6. export class SortedHeroesComponent extends HeroesBaseComponent {
7. constructor(heroService: HeroService) {
8. super(heroService);
9. }
10.
Now take note of the afterGetHeroes method. Our 嘀rst instinct was to create an
ngOnInit method in SortedHeroesComponent and do the sorting there. But
Angular calls the derived class's ngOnInit before calling the base class's
ngOnInit so we'd be sorting the heroes array before they arrived. That produces a
nasty error.
There is no public API for acquiring a parent reference. But because every
component instance is added to an injector's container, we can use Angular
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 35/47
11/20/2016 Dependency Injection ts COOKBOOK
In the following example, the parent AlexComponent has several children including
a CathyComponent :
@Component({
selector: 'alex',
template: `
<div class="a">
<h3>{{name}}</h3>
<cathy></cathy>
<craig></craig>
<carol></carol>
</div>`,
})
export class AlexComponent extends Base
{
name= 'Alex';
}
Cathy reports whether or not she has access to Alex after injecting an
AlexComponent into her constructor:
parent-嘀nder.component.ts (CathyComponent)
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 36/47
11/20/2016 Dependency Injection ts COOKBOOK
@Component({
selector: 'cathy',
template: `
<div class="c">
<h3>Cathy</h3>
{{alex ? 'Found' : 'Did not find'}} Alex via the component
class.<br>
</div>`
})
export class CathyComponent {
constructor( @Optional() public alex: AlexComponent ) { }
}
We added the @Optional quali嘀er for safety but the live example con嘀rms that the
alex parameter is set.
The app probably de嘀nes more than a dozen 嘀nancial instrument components. If
we're lucky, they all implement the same base class whose API our
NewsComponent understands.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 37/47
11/20/2016 Dependency Injection ts COOKBOOK
We're not claiming this is good design. We are asking can a component inject its
parent via the parent's base class?
The sample's CraigComponent explores this question. Looking back we see that
the Alex component extends (inherits) from a class named Base .
The CraigComponent tries to inject Base into its alex constructor parameter
and reports if it succeeded.
parent-嘀nder.component.ts (CraigComponent)
@Component({
selector: 'craig',
template: `
<div class="c">
<h3>Craig</h3>
{{alex ? 'Found' : 'Did not find'}} Alex via the base class.
</div>`
})
export class CraigComponent {
constructor( @Optional() public alex: Base ) { }
}
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 38/47
11/20/2016 Dependency Injection ts COOKBOOK
Unfortunately, this does not work. The live example con嘀rms that the alex
parameter is null. We cannot inject a parent by its base class.
The parent must cooperate by providing an alias to itself in the name of a class-
interface token.
Recall that Angular always adds a component instance to its own injector; that's why
we could inject Alex into Carol earlier.
Parent is the provider's class-interface token. The forwardRef breaks the circular
reference we just created by having the AlexComponent refer to itself.
Carol, the third of Alex's child components, injects the parent into its parent
parameter, the same way we've done it before:
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 39/47
11/20/2016 Dependency Injection ts COOKBOOK
name= 'Carol';
constructor( @Optional() public parent: Parent ) { }
}
Barry is the problem. He needs to reach his parent, Alice, and also be a parent to
Carol. That means he must both inject the Parent class-interface to get Alice and
provide a Parent to satisfy Carol.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 40/47
11/20/2016 Dependency Injection ts COOKBOOK
Here's Barry:
parent-嘀nder.component.ts (BarryComponent)
const templateB = `
<div class="b">
<div>
<h3>{{name}}</h3>
<p>My parent is {{parent?.name}}</p>
</div>
<carol></carol>
<chris></chris>
</div>`;
@Component({
selector: 'barry',
template: templateB,
providers: [{ provide: Parent, useExisting: forwardRef(() =>
BarryComponent) }]
})
export class BarryComponent implements Parent {
name = 'Barry';
constructor( @SkipSelf() @Optional() public parent: Parent ) { }
}
Barry's providers array looks just like Alex's. If we're going to keep writing alias
providers like this we should create a helper function.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 41/47
11/20/2016 Dependency Injection ts COOKBOOK
It's identical to Carol's constructor except for the additional @SkipSelf decorator.
1. It tell the injector to start its search for a Parent dependency in a component
above itself, which is what parent means.
-> BethComponent)
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 42/47
11/20/2016 Dependency Injection ts COOKBOOK
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 43/47
11/20/2016 Dependency Injection ts COOKBOOK
The Parent class-interface de嘀nes a name property with a type declaration but no
implementation., The name property is the only member of a parent component that
a child component can call. Such a narrowing interface helps decouple the child
component class from its parent components.
Doing so adds clarity to the code. But it's not technically necessary. Although the
AlexComponent has a name property (as required by its Base class) its class
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 44/47
11/20/2016 Dependency Injection ts COOKBOOK
Now we can add a simpler, more meaningful parent provider to our components:
providers: [ provideParent(AliceComponent) ]
We can do better. The current version of the helper function can only alias the
Parent class-interface. Our application might have a variety of parent types, each
Here's a revised version that defaults to parent but also accepts an optional
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 45/47
11/20/2016 Dependency Injection ts COOKBOOK
This isn't usually a problem, especially if we adhere to the recommended one class
per 嘀le rule. But sometimes circular references are unavoidable. We're in a bind
when class 'A refers to class 'B' and 'B' refers to 'A'. One of them has to be de嘀ned
嘀rst.
The Angular forwardRef function creates an indirect reference that Angular can
resolve later.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 46/47
11/20/2016 Dependency Injection ts COOKBOOK
The Parent Finder sample is full of circular class references that are impossible to
break.
We face this dilemma when a class makes a reference to itself as does the
AlexComponent in its providers array. The providers array is a property of
the @Component decorator function which must appear above the class de嘀nition.
https://angular.io/docs/ts/latest/cookbook/dependencyinjection.html 47/47