angular-cn/aio/content/guide/providers.md

79 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Providers
#### Prerequisites:
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app using the provider that this page describes,
see the <live-example></live-example>.
<hr>
## Create a service
You can provide services to your app by using the providers array in an NgModule.
Consider the default app generated by the CLI. In order to add a user service to it,
you can generate one by entering the following command in the terminal window:
```sh
ng generate service User
```
This creates a service called `UserService`. You now need to make the service available in your
app's injector. Update `app.module.ts` by importing it with your other import statements at the top
of the file and adding it to the providers array:
<code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example>
## Provider scope
When you add a service provider to the providers array of the root module, its available throughout the app. Additionally, when you import a module that has providers, those providers are also available to all the classes in the app as long they have the lookup token. For example, if you import the `HttpClientModule` into your `AppModule`, its providers are then available to the entire app and you can make HTTP requests from anywhere in your app.
## Limiting provider scope by lazy loading modules
In the basic CLI generated app, modules are eagerly loaded which means that they are all loaded when the app launches. Angular uses an injector system to make things available between modules. In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the app.
This behavior necessarily changes when you use lazy loading. Lazy loading is when you load modules only when you need them; for example, when routing. They arent loaded right away like with eagerly loaded modules. This means that any services listed in their provider arrays arent available because the root injector doesnt know about these modules.
<!-- KW--Make diagram here -->
<!-- KW--per Misko: not clear if the lazy modules are siblings or grand-children. They are both depending on router structure. -->
When the Angular router lazy-loads a module, it creates a new injector. This injector is a child of the root application injector. Imagine a tree of injectors; there is a single root injector and then a child injector for each lazy loaded module. The router adds all of the providers from the root injector to the child injector. When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers to the service instances of the application root injector.
Any component created within a lazy loaded modules context, such as by router navigation, gets the local instance of the service, not the instance in the root application injector. Components in external modules continue to receive the instance created for the application root.
Though you can provide services by lazy loading modules, not all services can be lazy loaded. For instance, some modules only work in the root module, such as the Router. The Router works with the global location object in the browser.
## Limiting provider scope with components
Another way to limit provider scope is by adding the service you want to limit to the components
`providers` array. Component providers and NgModule providers are independent of each other. This
method is helpful for when you want to eagerly load a module that needs a service all to itself.
Providing a service in the component limits the service only to that component (other components in
the same module cant access it.)
<code-example path="providers/src/app/app.component.ts" region="component-providers" title="src/app/app.component.ts" linenums="false">
</code-example>
## Providing services in modules vs. components
Generally, provide services the whole app needs in the root module and scope services by providing them in lazy loaded modules.
The router works at the root level so if you put providers in a component, even `AppComponent`, lazy loaded modules, which rely on the router, cant see them.
<!-- KW--Make a diagram here -->
Register a provider with a component when you must limit a service instance to a component and its component tree, that is, its child components. For example, a user editing component, `UserEditorComponent`, that needs a private copy of a caching `UserService` should register the `UserService` with the `UserEditorComponent`. Then each new instance of the `UserEditorComponent` gets its own cached service instance.
<hr>
## More on NgModules
You may also be interested in:
* [Singleton Services](guide/singleton-services), which elaborates on the concepts covered on this page.
* [Lazy Loading Modules](guide/lazy-loading-ngmodules).
* [NgModule FAQ](guide/ngmodule-faq).