Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update DI in action to recommend new way of defining providers #23076

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 20 additions & 63 deletions aio/content/guide/dependency-injection-in-action.md
Expand Up @@ -11,21 +11,18 @@ of the code in this cookbook.
{@a app-wide-dependencies}

## Application-wide dependencies
Register providers for dependencies used throughout the application in the root application component, `AppComponent`.

The following example shows importing and registering
the `LoggerService`, `UserContext`, and the `UserService`
in the `@Component` metadata `providers` array.


<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="import-services" title="src/app/app.component.ts (excerpt)" linenums="false">
Register providers for dependencies used throughout the application
in the `@Injectable()` decorator of the service itself.

<code-example path="dependency-injection/src/app/heroes/hero.service.3.ts" title="src/app/heroes/hero.service.3.ts" linenums="false">
</code-example>

`providedIn` here tells Angular that the root injector is responsible for creating an instance of the `HeroService`.
Services that are provided this way are automatically made available to the entire
application and don't need to be listed in any module.


All of these services are implemented as classes.
Service classes can act as their own providers which is why listing them in the `providers` array
Service classes can act as their own providers which is why defining them in the `@Injectable` decorator
is all the registration you need.

<div class="l-sub-section">
Expand All @@ -40,30 +37,21 @@ guide.
</div>



Now that you've registered these services,
Angular can inject them into the constructor of *any* component or service, *anywhere* in the application.

<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="ctor" title="src/app/hero-bios.component.ts (component constructor injection)" linenums="false">

</code-example>



<code-example path="dependency-injection-in-action/src/app/user-context.service.ts" region="ctor" title="src/app/user-context.service.ts (service constructor injection)" linenums="false">

</code-example>

{@a external-module-configuration}


## External module configuration
Generally, register providers in the `NgModule` rather than in the root application component.
If a provider cannot be configured in the `@Injectable` decorator of the service, then register application-wide providers in the root `AppModule`, not in the `AppComponent`. Generally, register providers in the `NgModule` rather than in the root application component.

Do this when you expect the service to be injectable everywhere,
or you are configuring another application global service _before the application starts_.
Do this when users should explicitly opt-in to use a service, or the service should be
provided in a lazily-loaded context,
or when you are configuring another application global service _before the application starts_.

Here is an example of the second case, where the component router configuration includes a non-default
Here is an example of the case where the component router configuration includes a non-default
[location strategy](guide/router#location-strategy) by listing its provider
in the `providers` list of the `AppModule`.

Expand Down Expand Up @@ -139,41 +127,7 @@ Notice the `@Injectable()`decorator on the `UserContextService` class.
</code-example>



That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`.

Technically, the `@Injectable()`decorator is only required for a service class that has _its own dependencies_.
The `LoggerService` doesn't depend on anything. The logger would work if you omitted `@Injectable()`
and the generated code would be slightly smaller.

But the service would break the moment you gave it a dependency and you'd have to go back
and add `@Injectable()` to fix it. Add `@Injectable()` from the start for the sake
of consistency and to avoid future pain.


<div class="alert is-helpful">



Although this site recommends applying `@Injectable()` to all service classes, don't feel bound by it.
Some developers prefer to add it only where needed and that's a reasonable policy too.


</div>



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



The `AppComponent` class had two dependencies as well but no `@Injectable()`.
It didn't need `@Injectable()` because that component class has the `@Component` decorator.
In Angular with TypeScript, a *single* decorator&mdash;*any* decorator&mdash;is sufficient to identify dependency types.



</div>
The `@Injectable` decorator indicates that the Angular DI system is used to create one or more instances of `UserContextService`.

{@a service-scope}

Expand Down Expand Up @@ -495,7 +449,7 @@ If the search is futile, the injector throws an error&mdash;unless the request w
A new injector has no providers.
Angular initializes the injectors it creates with some providers it cares about.
You have to register your _own_ application providers manually,
usually in the `providers` array of the `Component` or `Directive` metadata:
usually in the `@Injectable` decorator of the service, `providers` array of the `NgModule` or `Directive` metadata:

<code-example path="dependency-injection-in-action/src/app/app.component.ts" region="providers" title="src/app/app.component.ts (providers)">

Expand All @@ -508,15 +462,18 @@ usually in the `providers` array of the `Component` or `Directive` metadata:

### Defining providers

The simple class provider is the most typical by far.
You mention the class in the `providers` array and you're done.
The simple way of defining providers in the `@Injectable` decorator of the class is recommended.

<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.0.ts" linenums="false">
</code-example>

Another alternative is to mention the class in the providers array of the `@NgModule` and you're done.

<code-example path="dependency-injection-in-action/src/app/hero-bios.component.ts" region="class-provider" title="src/app/hero-bios.component.ts (class provider)" linenums="false">

</code-example>



It's that simple because the most common injected service is an instance of a class.
But not every dependency can be satisfied by creating a new instance of a class.
You need other ways to deliver dependency values and that means you need other ways to specify a provider.
Expand Down