Lesson 5 of the Tour of Heroes tutorial introduces services.
On a recent episode of the Adventures in Angular podcast, guest Pascal Precht made the recommendation that developers should get in the habit of always applying the @Injectable decorator to a service. The reason behind that recommendation is because the decorators (@Component, @Injectable, etc.) cause the emission of metdata needed to work out the dependency injection hierarchy, and there's no negative side-effects to adding the @Injectable decorator to a service even if that service doesn't itself have any dependencies. The tutorial essentially makes the same recommendation.
The dependency injection (DI) mechanism described in the lesson involves three parts:
-
Using an import statement to import the code of the service module/file
-
Using a constructor function in the component to assign the module variable defined with the import statement as a property of the component.
-
Adding the module variable defined with the import statement to the list of providers in the component's "providers" metadata property, "providing" a working instance of the service.
var AppComponent = (function () {
function AppComponent(heroService) {
this.heroService = heroService;
this.title = 'Tour of Heroes';
}
import { Hero } from './hero';
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'my-hero-subdetail',
template: `
<div>
<span>{{hero.name}} is kinda cool.</span>
</div>
`
})
export class HeroSubDetailComponent implements OnInit {
@Input()
hero: Hero;
ngOnInit() {
console.log( "sub-detail-component initialized" );
}
}
...and then added it to the existing HeroDetailComponent within an ngIf block that would only evaluate to true for the first hero:
import { HeroSubDetailComponent } from './hero-sub-detail.component';
@Component({
selector: 'my-hero-detail',
directives: [ HeroSubDetailComponent ],
template: `
<div>
<h2>{{hero.name}} details!</h2>
<div>
<label>id: </label>
{{hero.id}}
</div>
<div>
<label>name: </label>
{{hero.name}}
</div>
<div *ngIf="hero.id == 11">
<my-hero-subdetail [hero]="hero"></my-hero-subdetail>
</div>
</div>
`
})
...and as I suspected, every time the HeroSubDetailComponent was removed then re-added to the DOM as I clicked through different heroes, it would fire ngOnInit on the re-add.
I wasn't aware that Promises were added as native constructs in ES2015 (and thus in the latest implementation of TypeScript), so that was something I learned during this lesson. I was momentarily confused by how it was used without instantiating an instance of it: apparently the resolve() method is a static method, so in this case where the data is hard-coded in the application and immediately available it makes sense to go this route. But a note about the fact that in a more traditional use case you would instantiate a Promise instance might be warranted.