docs(ngmodule-faq): stronger, clearer advice on where to register providers (#2262)

This commit is contained in:
Ward Bell 2016-09-03 13:26:19 -07:00 committed by GitHub
parent 94a40a1852
commit 38bef16604
1 changed files with 39 additions and 17 deletions

View File

@ -33,12 +33,13 @@ block includes
* [Can I re-export imported classes and modules?](#q-re-export) * [Can I re-export imported classes and modules?](#q-re-export)
* [What is the _forRoot_ method?](#q-for-root) * [What is the _forRoot_ method?](#q-for-root)
Service Providers Service Providers
* [Why is a service provided in a feature module visible everywhere?](#q-module-provider-visibility) * [Why is a service provided in a feature module visible everywhere?](#q-module-provider-visibility)
* [Why is a service provided in a _lazy loaded_ module visible only to that module?](#q-lazy-loaded-module-provider-visibility) * [Why is a service provided in a _lazy loaded_ module visible only to that module?](#q-lazy-loaded-module-provider-visibility)
* [What if two modules provide the _same_ service?](#q-module-provider-duplicates) * [What if two modules provide the _same_ service?](#q-module-provider-duplicates)
* [How do I restrict service scope to a module?](#q-component-scoped-providers) * [How do I restrict service scope to a module?](#q-component-scoped-providers)
* [Should I add providers to the root _AppModule_ or the root _AppComponent_?](#q-root-component-or-module) * [Should I add app-wide providers to the root _AppModule_ or the root _AppComponent_?](#q-root-component-or-module)
* [Should I add other providers to a module or a component?](#q-component-or-module)
* [Why is it bad if _SharedModule_ provides a service to a lazy loaded module?](#q-why-bad) * [Why is it bad if _SharedModule_ provides a service to a lazy loaded module?](#q-why-bad)
* [Why does lazy loading create a child injector?](#q-why-child-injector) * [Why does lazy loading create a child injector?](#q-why-child-injector)
* [How can I tell if a module or service was previously loaded?](#q-is-it-loaded) * [How can I tell if a module or service was previously loaded?](#q-is-it-loaded)
@ -424,14 +425,21 @@ a#q-component-scoped-providers
a#q-root-component-or-module a#q-root-component-or-module
.l-main-section .l-main-section
:marked :marked
### Should I add providers to the root _AppModule_ or the root _AppComponent_? ### Should I add app-wide providers to the root _AppModule_ or the root _AppComponent_?
Most apps launch with an initial set of service providers. .alert.is-helpful
Should we register those providers on the root `AppModule` (`@NgModule.providers`) or :marked
the root `AppComponent` (`@Component.providers`)? Register application-wide providers in the root `AppModule`, not in the `AppComponent`.
:marked
Lazy-loaded modules and their components can inject `AppModule` services;
they cannot inject `AppComponent` services.
**_List such providers in the root_ `AppModule` _unless you have a compelling reason to do otherwise_**. Register a service in `AppComponent` providers _only_ if the service must be hidden
from components outside the `AppComponent` tree. This is a rare exceptional use case.
More generally, [prefer registering providers in modules](#q-component-or-module) to registering in components.
#### **_Discussion_:**
Angular registers all startup module providers with the application root injector. Angular registers all startup module providers with the application root injector.
The services created from root injector providers are available to the entire application. The services created from root injector providers are available to the entire application.
They are _application-scoped_. They are _application-scoped_.
@ -439,7 +447,7 @@ a#q-root-component-or-module
Certain services (e.g., the `Router`) only work when registered in the application root injector. Certain services (e.g., the `Router`) only work when registered in the application root injector.
By contrast, Angular registers `AppComponent` providers with the `AppComponent`'s own injector. By contrast, Angular registers `AppComponent` providers with the `AppComponent`'s own injector.
`AppComponent`services are available to that component and its component tree. `AppComponent`services are available only to that component and its component tree.
They are _component-scoped_. They are _component-scoped_.
The `AppComponent`'s injector is a _child_ of the root injector, one down in the injector hierarchy. The `AppComponent`'s injector is a _child_ of the root injector, one down in the injector hierarchy.
@ -448,19 +456,33 @@ a#q-root-component-or-module
`AppComponent` services don't exist at the root level where routing operates. `AppComponent` services don't exist at the root level where routing operates.
Lazy loaded modules can't reach them. Lazy loaded modules can't reach them.
In this sample applications, if we had registered `UserService` in the `AppComponent`, In the Angular Module Chapter sample applications, if we had registered `UserService` in the `AppComponent`,
the `HeroComponent` couldn't inject it. the `HeroComponent` couldn't inject it.
The application would fail the moment a user navigated to "Heroes". The application would fail the moment a user navigated to "Heroes".
We _can_ register a service in `AppComponent` providers if the app doesn't use routing. .l-hr
We _should_ register a service in `AppComponent` providers if the service must be hidden
from components outside the `AppComponent` tree. a#q-component-or-module
.l-main-section
:marked
### Should I add other providers to a module or a component?
In general, prefer registering feature-specific providers in modules (`@NgModule.providers`)
to registering in components (`@Component.providers`).
These are special cases. Register a provider with a component when you _must_ limit the scope of a service instance
When in doubt, register with the `AppModule`. to that component and its component tree.
Apply the same reasoning to registering a provider with a directive.
For example, a hero editing component that needs a private copy of a caching hero service should register
the `HeroService` with the `HeroEditorComponent`.
Then each new instance of the `HeroEditorComponent` gets its own cached service instance.
The changes that editor makes to heroes in its service do not touch the hero instances elsewhere in the application.
[Always register _application-wide_ services with the root `AppModule`](q-root-component-or-module),
not the root `AppComponent`.
.l-hr .l-hr
a#q-why-bad a#q-why-bad
.l-main-section .l-main-section
:marked :marked