Skip to content

Commit

Permalink
docs: recommend best practice for providers (#22934)
Browse files Browse the repository at this point in the history
PR Close #22934
  • Loading branch information
jbogarthyde authored and IgorMinar committed Apr 7, 2018
1 parent 33f8120 commit 1fac5f4
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 46 deletions.
5 changes: 0 additions & 5 deletions aio/content/examples/toh-pt4/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
Expand All @@ -19,13 +18,9 @@ import { MessagesComponent } from './messages/messages.component';
FormsModule
],
// #docregion providers
// #docregion providers-heroservice
providers: [
// #enddocregion providers-heroservice
// no need to place any providers due to the `providedIn` flag...
// #docregion providers-heroservice
],
// #enddocregion providers-heroservice
// #enddocregion providers
bootstrap: [ AppComponent ]
})
Expand Down
4 changes: 3 additions & 1 deletion aio/content/examples/toh-pt4/src/app/hero.service.1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { Hero } from './hero';
import { HEROES } from './mock-heroes';

// #docregion new
@Injectable({providedIn: 'root'})
@Injectable({
providedIn: 'root',
})
export class HeroService {

constructor() { }
Expand Down
4 changes: 3 additions & 1 deletion aio/content/examples/toh-pt4/src/app/hero.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { HEROES } from './mock-heroes';
import { MessageService } from './message.service';
// #enddocregion import-message-service

@Injectable({ providedIn: 'root' })
@Injectable({
providedIn: 'root',
})
export class HeroService {

// #docregion ctor
Expand Down
4 changes: 3 additions & 1 deletion aio/content/examples/toh-pt4/src/app/message.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
@Injectable({
providedIn: 'root',
})
export class MessageService {
messages: string[] = [];

Expand Down
68 changes: 30 additions & 38 deletions aio/content/tutorial/toh-pt4.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Using the Angular CLI, create a service called `hero`.
</code-example>

The command generates skeleton `HeroService` class in `src/app/hero.service.ts`
The `HeroService` class should look like the below.
The `HeroService` class should look like the following example.

<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
title="src/app/hero.service.ts (new service)" linenums="false">
Expand All @@ -40,19 +40,10 @@ The `HeroService` class should look like the below.
### _@Injectable()_ services

Notice that the new service imports the Angular `Injectable` symbol and annotates
the class with the `@Injectable()` decorator.
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).

The `@Injectable()` decorator tells Angular that this service _might_ itself
have injected dependencies.
It doesn't have dependencies now but [it will soon](#inject-message-service).
Whether it does or it doesn't, it's good practice to keep the decorator.

<div class="l-sub-section">

The Angular [style guidelines](guide/styleguide#style-07-04) strongly recommend keeping it
and the linter enforces this rule.

</div>
The `@Injectable()` decorator accepts a metadata object for the service, the same way the `@Component()` decorator did for your component classes.

### Get hero data

Expand All @@ -76,32 +67,39 @@ Add a `getHeroes` method to return the _mock heroes_.
{@a provide}
## Provide the `HeroService`

You must _provide_ the `HeroService` in the _dependency injection system_
You must make the `HeroService` available to the dependency injection system
before Angular can _inject_ it into the `HeroesComponent`,
as you will do [below](#inject).
as you will do [below](#inject). You do this 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.

There are several ways to provide the `HeroService`:
in the `HeroesComponent`, in the `AppComponent`, in the `AppModule`.
Each option has pros and cons.
Now, you need to make sure that the `HeroService` is registered as the provider of this service.
You are registering it with an _injector_, which is the object that is responsible for choosing and injecting the provider where it is required.

This tutorial chooses to provide it in the `AppModule`.
By default, the Angular CLI command `ng generate service` registers a provider with the _root injector_ for your service by including provider metadata in the `@Injectable` decorator.

That's such a popular choice that you could have told the CLI to provide it there automatically
by appending `--module=app`.
If you look at the `@Injectable()` statement right before the `HeroService` class definition, you can see that the `providedIn` metadata value is 'root':

<code-example language="sh" class="code-shell">
ng generate service hero --module=app
</code-example>
```
@Injectable({
providedIn: 'root',
})
```

Since you did not, you'll have to provide it yourself.
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.

Open the `AppModule` class, import the `HeroService`, and add it to the `@NgModule.providers` array.
<div class="l-sub-section">

<code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-heroservice">
If you need to, you can register providers at different levels:
in the `HeroesComponent`, in the `AppComponent`, in the `AppModule`.
For instance, you could have told the CLI to provide the service at the module level automatically by appending `--module=app`.

<code-example language="sh" class="code-shell">
ng generate service hero --module=app
</code-example>

The `providers` array tells Angular to create a single, shared instance of `HeroService`
and inject into any class that asks for it.
To learn more about providers and injectors, see the [Dependency Injection guide](guide/dependency-injection).

</div>

The `HeroService` is now ready to plug into the `HeroesComponent`.

Expand All @@ -111,17 +109,12 @@ This is a interim code sample that will allow you to provide and use the `HeroSe

</div>

<div class="alert is-helpful">

Learn more about _providers_ in the [Providers](guide/providers) guide.

</div>

## Update `HeroesComponent`

Open the `HeroesComponent` class file.

Delete the `HEROES` import as you won't need that anymore.
Delete the `HEROES` import, because you won't need that anymore.
Import the `HeroService` instead.

<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
Expand Down Expand Up @@ -295,10 +288,9 @@ You should see the default paragraph from `MessagesComponent` at the bottom of t
### Create the _MessageService_

Use the CLI to create the `MessageService` in `src/app`.
The `--module=app` option tells the CLI to [_provide_ this service](#provide) in the `AppModule`,

<code-example language="sh" class="code-shell">
ng generate service message --module=app
ng generate service message
</code-example>

Open `MessageService` and replace its contents with the following.
Expand Down Expand Up @@ -442,7 +434,7 @@ Here are the code files discussed on this page and your app should look like thi
## Summary

* You refactored data access to the `HeroService` class.
* You _provided_ the `HeroService` in the root `AppModule` so that it can be injected anywhere.
* You registered the `HeroService` as the _provider_ of its service at the root level so that it can be injected anywhere in the app.
* 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.
Expand Down

0 comments on commit 1fac5f4

Please sign in to comment.