Skip to content

Commit 2239bee

Browse files
committed
docs(docs-infra): traducción de guide/singleton-services.md
1 parent 8007394 commit 2239bee

File tree

2 files changed

+240
-87
lines changed

2 files changed

+240
-87
lines changed
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# Singleton services
2+
3+
A singleton service is a service for which only one instance exists in an app.
4+
5+
For a sample app using the app-wide singleton service that this page describes, see the
6+
<live-example name="ngmodules"></live-example> showcasing all the documented features of NgModules.
7+
8+
## Providing a singleton service
9+
10+
There are two ways to make a service a singleton in Angular:
11+
12+
* Set the `providedIn` property of the `@Injectable()` to `"root"`.
13+
* Include the service in the `AppModule` or in a module that is only imported by the `AppModule`
14+
15+
16+
{@a providedIn}
17+
18+
### Using `providedIn`
19+
20+
Beginning with Angular 6.0, the preferred way to create a singleton service is to set `providedIn` to `root` on the service's `@Injectable()` decorator. This tells Angular
21+
to provide the service in the application root.
22+
23+
<code-example path="providers/src/app/user.service.0.ts" header="src/app/user.service.ts"></code-example>
24+
25+
For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the
26+
[Tour of Heroes tutorial](tutorial).
27+
28+
### NgModule `providers` array
29+
30+
In apps built with Angular versions prior to 6.0, services are registered NgModule `providers` arrays as follows:
31+
32+
```ts
33+
@NgModule({
34+
...
35+
providers: [UserService],
36+
...
37+
})
38+
39+
```
40+
41+
If this NgModule were the root `AppModule`, the `UserService` would be a singleton and available
42+
throughout the app. Though you may see it coded this way, using the `providedIn` property of the `@Injectable()` decorator on the service itself is preferable as of Angular 6.0 as it makes your services tree-shakable.
43+
44+
{@a forRoot}
45+
46+
## The `forRoot()` pattern
47+
48+
Generally, you'll only need `providedIn` for providing services and `forRoot()`/`forChild()` for routing. However, understanding how `forRoot()` works to make sure a service is a singleton will inform your development at a deeper level.
49+
50+
If a module defines both providers and declarations (components, directives, pipes),
51+
then loading the module in multiple feature modules would duplicate the registration of the service. This could result in multiple service instances and the service would no longer behave as a singleton.
52+
53+
There are multiple ways to prevent this:
54+
55+
* Use the [`providedIn` syntax](guide/singleton-services#providedIn) instead of registering the service in the module.
56+
* Separate your services into their own module.
57+
* Define `forRoot()` and `forChild()` methods in the module.
58+
59+
<div class="alert is-helpful">
60+
61+
**Note:** There are two example apps where you can see this scenario; the more advanced <live-example noDownload name="ngmodules">NgModules live example</live-example>, which contains `forRoot()` and `forChild()` in the routing modules and the `GreetingModule`, and the simpler <live-example name="lazy-loading-ngmodules" noDownload>Lazy Loading live example</live-example>. For an introductory explanation see the [Lazy Loading Feature Modules](guide/lazy-loading-ngmodules) guide.
62+
63+
</div>
64+
65+
66+
Use `forRoot()` to
67+
separate providers from a module so you can import that module into the root module
68+
with `providers` and child modules without `providers`.
69+
70+
1. Create a static method `forRoot()` on the module.
71+
2. Place the providers into the `forRoot()` method.
72+
73+
<code-example path="ngmodules/src/app/greeting/greeting.module.ts" region="for-root" header="src/app/greeting/greeting.module.ts"></code-example>
74+
75+
76+
{@a forRoot-router}
77+
78+
### `forRoot()` and the `Router`
79+
80+
`RouterModule` provides the `Router` service, as well as router directives, such as `RouterOutlet` and `routerLink`. The root application module imports `RouterModule` so that the application has a `Router` and the root application components can access the router directives. Any feature modules must also import `RouterModule` so that their components can place router directives into their templates.
81+
82+
If the `RouterModule` didn’t have `forRoot()` then each feature module would instantiate a new `Router` instance, which would break the application as there can only be one `Router`. By using the `forRoot()` method, the root application module imports `RouterModule.forRoot(...)` and gets a `Router`, and all feature modules import `RouterModule.forChild(...)` which does not instantiate another `Router`.
83+
84+
<div class="alert is-helpful">
85+
86+
**Note:** If you have a module which has both providers and declarations,
87+
you _can_ use this
88+
technique to separate them out and you may see this pattern in legacy apps.
89+
However, since Angular 6.0, the best practice for providing services is with the
90+
`@Injectable()` `providedIn` property.
91+
92+
</div>
93+
94+
### How `forRoot()` works
95+
96+
`forRoot()` takes a service configuration object and returns a
97+
[ModuleWithProviders](api/core/ModuleWithProviders), which is
98+
a simple object with the following properties:
99+
100+
* `ngModule`: in this example, the `GreetingModule` class
101+
* `providers`: the configured providers
102+
103+
In the <live-example name="ngmodules">live example</live-example>
104+
the root `AppModule` imports the `GreetingModule` and adds the
105+
`providers` to the `AppModule` providers. Specifically,
106+
Angular accumulates all imported providers
107+
before appending the items listed in `@NgModule.providers`.
108+
This sequence ensures that whatever you add explicitly to
109+
the `AppModule` providers takes precedence over the providers
110+
of imported modules.
111+
112+
The sample app imports `GreetingModule` and uses its `forRoot()` method one time, in `AppModule`. Registering it once like this prevents multiple instances.
113+
114+
You can also add a `forRoot()` method in the `GreetingModule` that configures
115+
the greeting `UserService`.
116+
117+
In the following example, the optional, injected `UserServiceConfig`
118+
extends the greeting `UserService`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config.
119+
120+
<code-example path="ngmodules/src/app/greeting/user.service.ts" region="ctor" header="src/app/greeting/user.service.ts (constructor)"></code-example>
121+
122+
Here's `forRoot()` that takes a `UserServiceConfig` object:
123+
124+
<code-example path="ngmodules/src/app/greeting/greeting.module.ts" region="for-root" header="src/app/greeting/greeting.module.ts (forRoot)"></code-example>
125+
126+
Lastly, call it within the `imports` list of the `AppModule`. In the following
127+
snippet, other parts of the file are left out. For the complete file, see the <live-example name="ngmodules"></live-example>, or continue to the next section of this document.
128+
129+
<code-example path="ngmodules/src/app/app.module.ts" region="import-for-root" header="src/app/app.module.ts (imports)"></code-example>
130+
131+
The app displays "Miss Marple" as the user instead of the default "Sherlock Holmes".
132+
133+
Remember to import `GreetingModule` as a Javascript import at the top of the file and don't add it to more than one `@NgModule` `imports` list.
134+
135+
## Prevent reimport of the `GreetingModule`
136+
137+
Only the root `AppModule` should import the `GreetingModule`. If a
138+
lazy-loaded module imports it too, the app can generate
139+
[multiple instances](guide/ngmodule-faq#q-why-bad) of a service.
140+
141+
To guard against a lazy loaded module re-importing `GreetingModule`, add the following `GreetingModule` constructor.
142+
143+
<code-example path="ngmodules/src/app/greeting/greeting.module.ts" region="ctor" header="src/app/greeting/greeting.module.ts"></code-example>
144+
145+
The constructor tells Angular to inject the `GreetingModule` into itself.
146+
The injection would be circular if Angular looked for
147+
`GreetingModule` in the _current_ injector, but the `@SkipSelf()`
148+
decorator means "look for `GreetingModule` in an ancestor
149+
injector, above me in the injector hierarchy."
150+
151+
By default, the injector throws an error when it can't
152+
find a requested provider.
153+
The `@Optional()` decorator means not finding the service is OK.
154+
The injector returns `null`, the `parentModule` parameter is null,
155+
and the constructor concludes uneventfully.
156+
157+
It's a different story if you improperly import `GreetingModule` into a lazy loaded module such as `CustomersModule`.
158+
159+
Angular creates a lazy loaded module with its own injector,
160+
a child of the root injector.
161+
`@SkipSelf()` causes Angular to look for a `GreetingModule` in the parent injector, which this time is the root injector.
162+
Of course it finds the instance imported by the root `AppModule`.
163+
Now `parentModule` exists and the constructor throws the error.
164+
165+
Here are the two files in their entirety for reference:
166+
167+
<code-tabs>
168+
<code-pane header="app.module.ts" path="ngmodules/src/app/app.module.ts">
169+
</code-pane>
170+
<code-pane header="greeting.module.ts" region="whole-greeting-module" path="ngmodules/src/app/greeting/greeting.module.ts">
171+
</code-pane>
172+
</code-tabs>
173+
174+
<hr />
175+
176+
## More on NgModules
177+
178+
You may also be interested in:
179+
* [Sharing Modules](guide/sharing-ngmodules), which elaborates on the concepts covered on this page.
180+
* [Lazy Loading Modules](guide/lazy-loading-ngmodules).
181+
* [NgModule FAQ](guide/ngmodule-faq).

0 commit comments

Comments
 (0)