From 1fac5f4eb16204d677bba4206a643239274523c6 Mon Sep 17 00:00:00 2001 From: Judy Bogart Date: Thu, 22 Mar 2018 10:37:50 -0700 Subject: [PATCH] docs: recommend best practice for providers (#22934) PR Close #22934 --- .../examples/toh-pt4/src/app/app.module.ts | 5 -- .../toh-pt4/src/app/hero.service.1.ts | 4 +- .../examples/toh-pt4/src/app/hero.service.ts | 4 +- .../toh-pt4/src/app/message.service.ts | 4 +- aio/content/tutorial/toh-pt4.md | 68 ++++++++----------- 5 files changed, 39 insertions(+), 46 deletions(-) diff --git a/aio/content/examples/toh-pt4/src/app/app.module.ts b/aio/content/examples/toh-pt4/src/app/app.module.ts index 95306bb2f3f6a..f0265dacbacc0 100644 --- a/aio/content/examples/toh-pt4/src/app/app.module.ts +++ b/aio/content/examples/toh-pt4/src/app/app.module.ts @@ -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'; @@ -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 ] }) diff --git a/aio/content/examples/toh-pt4/src/app/hero.service.1.ts b/aio/content/examples/toh-pt4/src/app/hero.service.1.ts index 408dc3945b0a0..1e017b379fb9b 100644 --- a/aio/content/examples/toh-pt4/src/app/hero.service.1.ts +++ b/aio/content/examples/toh-pt4/src/app/hero.service.1.ts @@ -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() { } diff --git a/aio/content/examples/toh-pt4/src/app/hero.service.ts b/aio/content/examples/toh-pt4/src/app/hero.service.ts index 7e4e2ba30ccda..1095915552a81 100644 --- a/aio/content/examples/toh-pt4/src/app/hero.service.ts +++ b/aio/content/examples/toh-pt4/src/app/hero.service.ts @@ -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 diff --git a/aio/content/examples/toh-pt4/src/app/message.service.ts b/aio/content/examples/toh-pt4/src/app/message.service.ts index 30614a8af4f42..d72412e115ebe 100644 --- a/aio/content/examples/toh-pt4/src/app/message.service.ts +++ b/aio/content/examples/toh-pt4/src/app/message.service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@angular/core'; -@Injectable({ providedIn: 'root' }) +@Injectable({ + providedIn: 'root', +}) export class MessageService { messages: string[] = []; diff --git a/aio/content/tutorial/toh-pt4.md b/aio/content/tutorial/toh-pt4.md index b6996ce15953d..c5a87b2ff7865 100644 --- a/aio/content/tutorial/toh-pt4.md +++ b/aio/content/tutorial/toh-pt4.md @@ -31,7 +31,7 @@ Using the Angular CLI, create a service called `hero`. 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. @@ -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. - -
- -The Angular [style guidelines](guide/styleguide#style-07-04) strongly recommend keeping it -and the linter enforces this rule. - -
+The `@Injectable()` decorator accepts a metadata object for the service, the same way the `@Component()` decorator did for your component classes. ### Get hero data @@ -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': - - ng generate service hero --module=app - +``` +@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. +
- +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`. + + + ng generate service hero --module=app -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). + +
The `HeroService` is now ready to plug into the `HeroesComponent`. @@ -111,17 +109,12 @@ This is a interim code sample that will allow you to provide and use the `HeroSe -
- - Learn more about _providers_ in the [Providers](guide/providers) guide. - -
## 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. @@ -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`, - ng generate service message --module=app + ng generate service message Open `MessageService` and replace its contents with the following. @@ -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.