Skip to content

Commit

Permalink
docs: edits
Browse files Browse the repository at this point in the history
  • Loading branch information
kapunahelewong committed Mar 5, 2019
1 parent 94ec56a commit b8d23ef
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 41 deletions.
67 changes: 26 additions & 41 deletions aio/content/guide/hierarchical-dependency-injection.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ There are two injector hierarchies in Angular:

<!-- use NgModule to configure a ModuleInjector Configured using the providers on the NgModule. It's a runtime representation of that configuration. A ModuleInjector can be configured usign an NgModule or the @Injectable annotation. The way you configure a ModuleInjector is explicitly (NgModule.providers), or implicitly in a tree-shakable with @Injectable.providedIn. -->

1. `ElementInjector`&mdash;created implicitly at each DOM element. An `ElementInjector` is usually
1. `ElementInjector`&mdash;created implicitly at each DOM element. An `ElementInjector` is by default
empty unless you configure it in the `providers` property on `@Directive()` or `@Component()`.


Expand All @@ -19,7 +19,7 @@ empty unless you configure it in the `providers` property on `@Directive()` or `

### `ModuleInjector`

A `ModuleInjector` is created in one of two ways:
Angular creates a `ModuleInjector` in one of two ways:

1. The `@Injectable()` `providedIn` property configured with an @NgModule, such as `root` or
a lazy loaded feature module.
Expand All @@ -29,21 +29,19 @@ a lazy loaded feature module.
<div class="is-helpful alert">

**Note:** Using the `@Injectable()` `providedIn` property is preferable to the `@NgModule()` `providers`
array because with `@Injectable()` `providedIn`, optimization tools such as those used by the CLI's
production builds can perform tree shaking, which removes services that your app isn't using.
Tree shaking results in smaller bundle sizes.
array because with `@Injectable()` `providedIn`, optimization tools such as those the CLI uses can perform tree shaking, which removes services that your app isn't using and results in smaller bundle sizes.

Tree-shaking is especially useful for a library that offers a particular service that some
components *might* want to inject optionally,
and leave it up to the app whether to provide the service.

* Learn more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers).
* Read more about [tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers) in [DI Providers](guide/dependency-injection-providers).

</div>

If an @NgModule imports other @NgModules, all of those providers from imported @NgModules are flattened into a single `ModuleInjector`. Create child `ModuleInjector`s by lazy loading other @NgModules, rather than by importing them.

Provide services in your service via the `providedIn` property of `@Injectable()` as follows:
Provide services with the `providedIn` property of `@Injectable()` as follows:

```ts

Expand All @@ -59,7 +57,7 @@ export class ItemService {
```


The `@Injectable()` decorator identifies a service class. The `providedIn` property configures a specific `ModuleInjector`, here `root`, which makes the service available anywhere the class is imported and ensures there's only one instance of the service.
The `@Injectable()` decorator identifies a service class. The `providedIn` property configures a specific `ModuleInjector`, here `root`, which makes the service available anywhere the class is imported.

Though the above example provides the `ItemService` in the `root` `ModuleInjector`, you can specify another `@NgModule`, as in the following section.

Expand Down Expand Up @@ -91,59 +89,46 @@ For a working example of providing a service in an NgModule other than `root`, s
<!-- Add example here (to do: build example within aio) -->


### Platform injector

<div class="alert is-helpful">

<h4>Platform injector</h4>
#### Platform injector

<!-- KW Is the following correct? Should we talk more about the platform injector? -->
<!-- There are two injectors further up the injector tree than `root`. The parent of `root` is a `ModuleInjector` configured by `PlatformModule` which has things like `DomSanitizer`. -->

Angular creates a `root` `ModuleInjector` when you call `platform.bootstrap`. While the name `root` is a special alias for this `ModuleInjector`, others don't have aliases. Additionally, you have the option to create `ModuleInjector`s whenever a dynamically loaded component is created, such as with the Router. The Router will create children of ModuleInjectors.

When you use `providedIn:'root'`, you are configuring the root `ModuleInjector`
for the app, which is the injector for `AppModule`.
The actual root of the entire injector hierarchy is a _platform injector_,
which is the parent of app-root injectors.
This allows multiple apps to share a platform configuration.
For example, a browser has only one URL bar, no matter how many apps you have running.

The platform injector is used internally during bootstrap to configure platform-specific dependencies. You can configure additional platform-specific providers at the platform level by supplying `extraProviders` using the `platformBrowser()` function.

If you only register providers with the root injector at the top level (typically the root `AppModule`), the tree of injectors appears to be flat.
All requests bubble up to the root injector, whether you configured it with the `bootstrapModule` method, or registered all providers with `root` in their own services.

<!-- Do we need to say "typically the root `AppModule`"? -->
There are two more injectors above `root`, an additional `ModuleInjector` and `NullInjector()`.

Learn more about dependency resolution through the injector hierarchy:
[What you always wanted to know about Angular Dependency Injection tree](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)



Though the `root` injector appears to be the root, there are actually two other injectors working behind the scenes. Angular bootstraps the app with the following method in `main.ts`:
Consider how Angular bootstraps the app with the following in `main.ts`:

```javascript
platformBrowserDynamic().bootstrapModule(AppModule).then(ref => {...})
```

The `platformBrowserDynamic()` method creates an injector configured by a `PlatformModule`. The `bootstrapModule()` method creates a child injector of the platform injector which is configured by the `AppModule`.
The `bootstrapModule()` method creates a child injector of the platform injector which is configured by the `AppModule`. This is the `root` `ModuleInjector`.

There are two injectors further up the injector tree than `root`. The parent of `root` is a `ModuleInjector` configured by `PlatformModule` which has things like `DomSanitizer`.
The `platformBrowserDynamic()` method creates an injector configured by a `PlatformModule`, which contains things such as DomSanitizer and other platform-specific dependencies. This allows multiple apps to share a platform configuration.
For example, a browser has only one URL bar, no matter how many apps you have running.
You can configure additional platform-specific providers at the platform level by supplying `extraProviders` using the `platformBrowser()` function.

The next parent injector in the hierarchy is the `NullInjector()`, which is the top of the tree. If you've gone so far up the tree that you are looking for a service in the `NullInjector()`, you'll get an error unless you've used `@Optional()` because ultimately, everything ends at the `NullInjector()` and it returns an error or, in the case of `@Optional()`, `null`.

NullInjector() => I always throw an error unless you use @Optional
ModuleInjector(configured by PlatformModule) => I have special things like DomSanitizer => platformBrowser()
ModuleInjector(configured by AppModule) => I have things for your application => bootstrapModule(AppModule)
The following diagram represents the relationship between the `root` `ModuleInjector` and its parent injectors as the previous paragraphs describe.

<figure>
<img src="generated/images/guide/dependency-injection/injectors.svg" alt="NullInjector, ModuleInjector, root injector">
</figure>

While the name `root` is a special alias, other `ModuleInjector`s don't have aliases. You have the option to create `ModuleInjector`s whenever a dynamically loaded component is created, such as with the Router, which will create child `ModuleInjector`s.

If you only register providers with the root injector at the top level, the tree of injectors appears to be flat.
All requests bubble up to the root injector, whether you configured it with the `bootstrapModule()` method, or registered all providers with `root` in their own services.

Learn more about dependency resolution through the injector hierarchy:
[What you always wanted to know about Angular Dependency Injection tree](https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)


</div>

<div class="alert is-helpful">

<h4>`@Injectable()` vs `@NgModule()`</h4>
<h4>@Injectable() vs @NgModule()</h4>

If you configure a app-wide provider in the `@NgModule()` metadata for AppModule, it overrides one configured for `root` in the `@Injectable()` metadata. You can do this to configure a non-default provider of a service that is shared with multiple apps.

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b8d23ef

Please sign in to comment.