2020-02-03 13:49:03 -05:00
# Add services
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The Tour of Heroes `HeroesComponent` is currently getting and displaying fake data.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
After the refactoring in this tutorial, `HeroesComponent` will be lean and focused on supporting the view.
2017-11-29 14:43:54 -05:00
It will also be easier to unit-test with a mock service.
2017-03-31 19:57:13 -04:00
2020-04-10 13:10:59 -04:00
< div class = "alert is-helpful" >
For the sample app that this page describes, see the < live-example > < / live-example > .
< / div >
2017-11-06 13:02:18 -05:00
## Why services
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data.
They should focus on presenting data and delegate data access to a service.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
In this tutorial, you'll create a `HeroService` that all application classes can use to get heroes.
2020-01-13 13:37:43 -05:00
Instead of creating that service with the [`new` keyword ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new ),
you'll rely on Angular [*dependency injection* ](guide/dependency-injection )
2017-11-06 13:02:18 -05:00
to inject it into the `HeroesComponent` constructor.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Services are a great way to share information among classes that _don't know each other_ .
2019-12-28 01:31:54 -05:00
You'll create a `MessageService` and inject it in two places.
2017-02-22 13:09:39 -05:00
2019-12-28 01:31:54 -05:00
1. Inject in HeroService, which uses the service to send a message.
2. Inject in MessagesComponent, which displays that message, and also displays the ID
when the user clicks a hero.
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
## Create the `HeroService`
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
Using the Angular CLI, create a service called `hero` .
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-11-06 13:02:18 -05:00
ng generate service hero
2017-02-22 13:09:39 -05:00
< / code-example >
2019-01-31 14:25:30 -05:00
The command generates a skeleton `HeroService` class in `src/app/hero.service.ts` as follows:
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< code-example path = "toh-pt4/src/app/hero.service.1.ts" region = "new"
2019-07-20 13:40:17 -04:00
header="src/app/hero.service.ts (new service)">< / code-example >
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
### `@Injectable()` services
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Notice that the new service imports the Angular `Injectable` symbol and annotates
2018-03-22 13:37:50 -04:00
the class with the `@Injectable()` decorator. This marks the class as one that participates in the _dependency injection system_ . The `HeroService` class is going to provide an injectable service, and it can also have its own injected dependencies.
It doesn't have any dependencies yet, but [it will soon ](#inject-message-service ).
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
The `@Injectable()` decorator accepts a metadata object for the service, the same way the `@Component()` decorator did for your component classes.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
### Get hero data
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
The `HeroService` could get hero data from anywhere— a web service, local storage, or a mock data source.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
Removing data access from components means you can change your mind about the implementation anytime, without touching any components.
They don't know how the service works.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The implementation in _this_ tutorial will continue to deliver _mock heroes_ .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Import the `Hero` and `HEROES` .
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/hero.service.ts" header = "src/app/hero.service.ts" region = "import-heroes" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-11-06 13:02:18 -05:00
Add a `getHeroes` method to return the _mock heroes_ .
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/hero.service.1.ts" header = "src/app/hero.service.ts" region = "getHeroes" >
2017-11-06 13:02:18 -05:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
{@a provide}
## Provide the `HeroService`
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
You must make the `HeroService` available to the dependency injection system
before Angular can _inject_ it into the `HeroesComponent` by registering a _provider_ . A provider is something that can create or deliver a service; in this case, it instantiates the `HeroService` class to provide the service.
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
To make sure that the `HeroService` can provide this service, register it
with the _injector_ , which is the object that is responsible for choosing
and injecting the provider where the app requires it.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata, that is `providedIn: 'root'` in the `@Injectable()` decorator.
2017-03-31 19:57:13 -04:00
2018-03-22 13:37:50 -04:00
```
@Injectable ({
providedIn: 'root',
})
```
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
When you provide the service at the root level, Angular creates a single, shared instance of `HeroService` and injects into any class that asks for it.
Registering the provider in the `@Injectable` metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.
2017-02-22 13:09:39 -05:00
2018-07-19 18:00:08 -04:00
< div class = "alert is-helpful" >
2017-02-22 13:09:39 -05:00
2018-08-01 09:28:33 -04:00
To learn more about providers, see the [Providers section ](guide/providers ).
To learn more about injectors, see the [Dependency Injection guide ](guide/dependency-injection ).
2018-03-22 13:37:50 -04:00
< / div >
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
The `HeroService` is now ready to plug into the `HeroesComponent` .
2017-03-31 19:57:13 -04:00
2017-12-30 21:37:11 -05:00
< div class = "alert is-important" >
2019-10-26 10:35:03 -04:00
This is an interim code sample that will allow you to provide and use the `HeroService` . At this point, the code will differ from the `HeroService` in the ["final code review" ](#final-code-review ).
2017-12-30 21:37:11 -05:00
< / div >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
## Update `HeroesComponent`
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Open the `HeroesComponent` class file.
2017-02-22 13:09:39 -05:00
2018-03-22 13:37:50 -04:00
Delete the `HEROES` import, because you won't need that anymore.
2017-11-06 13:02:18 -05:00
Import the `HeroService` instead.
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.ts" header = "src/app/heroes/heroes.component.ts (import HeroService)" region = "hero-service-import" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-12-29 17:36:22 -05:00
Replace the definition of the `heroes` property with a simple declaration.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.ts" header = "src/app/heroes/heroes.component.ts" region = "heroes" >
2017-11-06 13:02:18 -05:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
{@a inject}
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
### Inject the `HeroService`
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Add a private `heroService` parameter of type `HeroService` to the constructor.
2017-02-22 13:09:39 -05:00
2020-02-11 22:39:02 -05:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.1.ts" header = "src/app/heroes/heroes.component.ts" region = "ctor" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
When Angular creates a `HeroesComponent` , the [Dependency Injection ](guide/dependency-injection ) system
2019-01-31 14:25:30 -05:00
sets the `heroService` parameter to the singleton instance of `HeroService` .
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
### Add `getHeroes()`
2017-02-22 13:09:39 -05:00
2020-03-31 14:21:21 -04:00
Create a method to retrieve the heroes from the service.
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.1.ts" header = "src/app/heroes/heroes.component.ts" region = "getHeroes" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
{@a oninit}
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
### Call it in `ngOnInit()`
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
While you could call `getHeroes()` in the constructor, that's not the best practice.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Reserve the constructor for simple initialization such as wiring constructor parameters to properties.
The constructor shouldn't _do anything_ .
It certainly shouldn't call a function that makes HTTP requests to a remote server as a _real_ data service would.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook* ](guide/lifecycle-hooks ) and
2019-01-31 14:25:30 -05:00
let Angular call `ngOnInit()` at an appropriate time _after_ constructing a `HeroesComponent` instance.
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.ts" header = "src/app/heroes/heroes.component.ts" region = "ng-on-init" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
### See it run
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
After the browser refreshes, the app should run as before,
2017-11-06 13:02:18 -05:00
showing a list of heroes and a hero detail view when you click on a hero name.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
## Observable data
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The `HeroService.getHeroes()` method has a _synchronous signature_ ,
which implies that the `HeroService` can fetch heroes synchronously.
2019-01-31 14:25:30 -05:00
The `HeroesComponent` consumes the `getHeroes()` result
2017-11-06 13:02:18 -05:00
as if heroes could be fetched synchronously.
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/heroes/heroes.component.1.ts" header = "src/app/heroes/heroes.component.ts" region = "get-heroes" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
This will not work in a real app.
You're getting away with it now because the service currently returns _mock heroes_ .
2019-01-31 14:25:30 -05:00
But soon the app will fetch heroes from a remote server,
2017-11-06 13:02:18 -05:00
which is an inherently _asynchronous_ operation.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
The `HeroService` must wait for the server to respond,
`getHeroes()` cannot return immediately with hero data,
and the browser will not block while the service waits.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
`HeroService.getHeroes()` must have an _asynchronous signature_ of some kind.
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
In this tutorial, `HeroService.getHeroes()` will return an `Observable`
2019-01-31 14:25:30 -05:00
because it will eventually use the Angular `HttpClient.get` method to fetch the heroes
2017-11-06 13:02:18 -05:00
and [`HttpClient.get()` returns an `Observable` ](guide/http ).
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
### Observable `HeroService`
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
`Observable` is one of the key classes in the [RxJS library ](http://reactivex.io/rxjs/ ).
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
In a [later tutorial on HTTP ](tutorial/toh-pt6 ), you'll learn that Angular's `HttpClient` methods return RxJS `Observable` s.
In this tutorial, you'll simulate getting data from the server with the RxJS `of()` function.
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
Open the `HeroService` file and import the `Observable` and `of` symbols from RxJS.
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/hero.service.ts" header = "src/app/hero.service.ts (Observable imports)" region = "import-observable" >
2017-03-27 11:08:53 -04:00
< / code-example >
2019-01-31 14:25:30 -05:00
Replace the `getHeroes()` method with the following:
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/hero.service.ts" header = "src/app/hero.service.ts" region = "getHeroes-1" > < / code-example >
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
`of(HEROES)` returns an `Observable<Hero[]>` that emits _a single value_ , the array of mock heroes.
2017-02-22 13:09:39 -05:00
2018-07-19 18:00:08 -04:00
< div class = "alert is-helpful" >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
In the [HTTP tutorial ](tutorial/toh-pt6 ), you'll call `HttpClient.get<Hero[]>()` which also returns an `Observable<Hero[]>` that emits _a single value_ , an array of heroes from the body of the HTTP response.
2017-02-22 13:09:39 -05:00
2017-04-10 11:51:13 -04:00
< / div >
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
### Subscribe in `HeroesComponent`
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
The `HeroService.getHeroes` method used to return a `Hero[]` .
Now it returns an `Observable<Hero[]>` .
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
You'll have to adjust to that difference in `HeroesComponent` .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Find the `getHeroes` method and replace it with the following code
(shown side-by-side with the previous version for comparison)
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< code-tabs >
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-pane header = "heroes.component.ts (Observable)"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes">
< / code-pane >
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
< code-pane header = "heroes.component.ts (Original)"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
< / code-pane >
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
< / code-tabs >
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
`Observable.subscribe()` is the critical difference.
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
The previous version assigns an array of heroes to the component's `heroes` property.
The assignment occurs _synchronously_ , as if the server could return heroes instantly
or the browser could freeze the UI while it waited for the server's response.
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
That _won't work_ when the `HeroService` is actually making requests of a remote server.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
The new version waits for the `Observable` to emit the array of heroes— which
could happen now or several minutes from now.
The `subscribe()` method passes the emitted array to the callback,
2017-11-06 13:02:18 -05:00
which sets the component's `heroes` property.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
This asynchronous approach _will work_ when
the `HeroService` requests heroes from the server.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
## Show messages
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
This section guides you through the following:
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
* adding a `MessagesComponent` that displays app messages at the bottom of the screen
* creating an injectable, app-wide `MessageService` for sending messages to be displayed
* injecting `MessageService` into the `HeroService`
* displaying a message when `HeroService` fetches heroes successfully
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
### Create `MessagesComponent`
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Use the CLI to create the `MessagesComponent` .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
< code-example language = "sh" class = "code-shell" >
ng generate component messages
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2019-03-19 07:57:38 -04:00
The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule` .
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
Modify the `AppComponent` template to display the generated `MessagesComponent` .
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< code-example
2019-01-31 14:25:30 -05:00
header = "src/app/app.component.html"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/app.component.html">
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
You should see the default paragraph from `MessagesComponent` at the bottom of the page.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
### Create the `MessageService`
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
Use the CLI to create the `MessageService` in `src/app` .
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
< code-example language = "sh" class = "code-shell" >
2018-03-22 13:37:50 -04:00
ng generate service message
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Open `MessageService` and replace its contents with the following.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example header = "src/app/message.service.ts" path = "toh-pt4/src/app/message.service.ts" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
{@a inject-message-service}
### Inject it into the `HeroService`
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
In `HeroService` , import the `MessageService` .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
< code-example
2019-01-31 14:25:30 -05:00
header = "src/app/hero.service.ts (import MessageService)"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Modify the constructor with a parameter that declares a private `messageService` property.
2019-01-31 14:25:30 -05:00
Angular will inject the singleton `MessageService` into that property
2017-11-06 13:02:18 -05:00
when it creates the `HeroService` .
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< code-example
2019-01-31 14:25:30 -05:00
path="toh-pt4/src/app/hero.service.ts" header="src/app/hero.service.ts" region="ctor">
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2018-07-19 18:00:08 -04:00
< div class = "alert is-helpful" >
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
This is a typical "*service-in-service*" scenario:
you inject the `MessageService` into the `HeroService` which is injected into the `HeroesComponent` .
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-11-06 13:02:18 -05:00
### Send a message from `HeroService`
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
Modify the `getHeroes()` method to send a message when the heroes are fetched.
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/hero.service.ts" header = "src/app/hero.service.ts" region = "getHeroes" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
### Display the message from `HeroService`
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
The `MessagesComponent` should display all messages,
2017-11-06 13:02:18 -05:00
including the message sent by the `HeroService` when it fetches heroes.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
Open `MessagesComponent` and import the `MessageService` .
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
< code-example header = "src/app/messages/messages.component.ts (import MessageService)" path = "toh-pt4/src/app/messages/messages.component.ts" region = "import-message-service" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-11-06 13:02:18 -05:00
Modify the constructor with a parameter that declares a **public** `messageService` property.
2019-01-31 14:25:30 -05:00
Angular will inject the singleton `MessageService` into that property
2018-04-16 11:15:38 -04:00
when it creates the `MessagesComponent` .
2017-03-31 19:57:13 -04:00
2019-01-31 14:25:30 -05:00
< code-example path = "toh-pt4/src/app/messages/messages.component.ts" header = "src/app/messages/messages.component.ts" region = "ctor" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
The `messageService` property **must be public** because you're going to bind to it in the template.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
< div class = "alert is-important" >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
Angular only binds to _public_ component properties.
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2019-01-31 14:25:30 -05:00
### Bind to the `MessageService`
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
Replace the CLI-generated `MessagesComponent` template with the following.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< code-example
2018-10-11 07:29:59 -04:00
header = "src/app/messages/messages.component.html"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/messages/messages.component.html">
< / code-example >
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
This template binds directly to the component's `messageService` .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
* The `*ngIf` only displays the messages area if there are messages to show.
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
* An `*ngFor` presents the list of messages in repeated `<div>` elements.
2017-02-22 13:09:39 -05:00
2020-04-28 16:26:58 -04:00
* An Angular [event binding ](guide/event-binding ) binds the button's click event
2017-11-06 13:02:18 -05:00
to `MessageService.clear()` .
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
The messages will look better when you add the private CSS styles to `messages.component.css`
as listed in one of the ["final code review" ](#final-code-review ) tabs below.
2017-02-22 13:09:39 -05:00
2019-12-28 01:31:54 -05:00
## Add additional messages to hero service
The following example shows how to send and display a message each time the user clicks on
a hero, showing a history of the user's selections. This will be helpful when you get to the
next section on [Routing ](tutorial/toh-pt5 ).
< code-example header = "src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts">
< / code-example >
2017-11-06 13:02:18 -05:00
The browser refreshes and the page displays the list of heroes.
2019-12-28 01:31:54 -05:00
Refresh the browser to see the list of heroes, and scroll to the bottom to see the
messages from the HeroService. Each time you click a hero, a new message appears to record
the selection. Use the "clear" button to clear the message history.
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
{@a final-code-review}
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
## Final code review
2017-02-22 13:09:39 -05:00
2020-04-10 13:10:59 -04:00
Here are the code files discussed on this page.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-tabs >
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
< code-pane header = "src/app/hero.service.ts"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/hero.service.ts">
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2019-01-31 14:25:30 -05:00
< code-pane header = "src/app/message.service.ts"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/message.service.ts">
< / code-pane >
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/heroes/heroes.component.ts"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/heroes/heroes.component.ts">
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/messages/messages.component.ts"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/messages/messages.component.ts">
< / code-pane >
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/messages/messages.component.html"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/messages/messages.component.html">
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/messages/messages.component.css"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/messages/messages.component.css">
< / code-pane >
2017-02-22 13:09:39 -05:00
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/app.module.ts"
2017-12-30 21:37:11 -05:00
path="toh-pt4/src/app/app.module.ts">
< / code-pane >
2018-10-11 07:29:59 -04:00
< code-pane header = "src/app/app.component.html"
2017-11-06 13:02:18 -05:00
path="toh-pt4/src/app/app.component.html">
< / code-pane >
2017-03-31 19:57:13 -04:00
2017-11-06 13:02:18 -05:00
< / code-tabs >
2017-03-31 19:57:13 -04:00
2017-09-27 16:45:47 -04:00
## Summary
2017-02-22 13:09:39 -05:00
2017-11-06 13:02:18 -05:00
* You refactored data access to the `HeroService` class.
2018-03-22 13:37:50 -04:00
* You registered the `HeroService` as the _provider_ of its service at the root level so that it can be injected anywhere in the app.
2017-11-06 13:02:18 -05:00
* You used [Angular Dependency Injection ](guide/dependency-injection ) to inject it into a component.
* You gave the `HeroService` _get data_ method an asynchronous signature.
* You discovered `Observable` and the RxJS _Observable_ library.
2018-03-21 19:26:50 -04:00
* You used RxJS `of()` to return an observable of mock heroes (`Observable< Hero [] > `).
2017-11-06 13:02:18 -05:00
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
* You created a `MessageService` for loosely-coupled communication between classes.
* The `HeroService` injected into a component is created with another injected service,
`MessageService` .