diff --git a/public/docs/_examples/ngmodule/ts/app/hero/hero.module.3.ts b/public/docs/_examples/ngmodule/ts/app/hero/hero.module.3.ts index 327e528178..df590a441c 100644 --- a/public/docs/_examples/ngmodule/ts/app/hero/hero.module.3.ts +++ b/public/docs/_examples/ngmodule/ts/app/hero/hero.module.3.ts @@ -8,9 +8,14 @@ import { HeroListComponent } from './hero-list.component'; import { HighlightDirective } from './highlight.directive'; import { routing } from './hero.routing.3'; +// TODO: Remove in RC 6 +import { HeroService } from './hero.service'; + // #docregion class @NgModule({ imports: [ CommonModule, FormsModule, routing ], + // TODO: Remove in RC 6 + providers: [ HeroService ], declarations: [ HeroComponent, HeroDetailComponent, HeroListComponent, HighlightDirective diff --git a/public/docs/_examples/ngmodule/ts/app/hero/hero.module.ts b/public/docs/_examples/ngmodule/ts/app/hero/hero.module.ts index 5408205a3d..43e8e8e655 100644 --- a/public/docs/_examples/ngmodule/ts/app/hero/hero.module.ts +++ b/public/docs/_examples/ngmodule/ts/app/hero/hero.module.ts @@ -7,14 +7,12 @@ import { HeroDetailComponent } from './hero-detail.component'; import { HeroListComponent } from './hero-list.component'; import { routing } from './hero.routing'; -/* - * TODO: Remove THE HeroService class and provider after - * https://github.com/angular/angular/pull/10579 lands - */ +// TODO: Remove THE HeroService class in RC 6 import { HeroService } from './hero.service'; @NgModule({ imports: [ SharedModule, routing ], + // TODO: Remove in RC 6 providers: [ HeroService ], declarations: [ HeroComponent, HeroDetailComponent, HeroListComponent, diff --git a/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json b/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json index 77804a3be1..090a440059 100644 --- a/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json +++ b/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json @@ -9,11 +9,12 @@ "app/title.component.ts", "app/user.service.ts", - "app/contact/*.css", - "app/contact/*.html", - "app/contact/*.ts", - "!app/contact/contact.component.ts", - "!app/contact/contact.module.ts", + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.component.3.ts", + "app/contact/contact.service.ts", + "app/contact/highlight.directive.ts", "styles.css", "index.1b.html" diff --git a/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json b/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json index b7da9b879f..4ee4638a63 100644 --- a/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json +++ b/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json @@ -9,12 +9,14 @@ "app/title.component.ts", "app/user.service.ts", - "app/contact/*.css", - "app/contact/*.html", - "app/contact/*.ts", - "!app/contact/contact.component.ts", - "!app/contact/contact.module.ts", - "!app/contact/contact.module.3.ts", + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.service.ts", + + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.3.ts", + "app/contact/contact.module.2.ts", + "app/contact/highlight.directive.ts", "styles.css", "index.2.html" diff --git a/public/docs/_examples/ngmodule/ts/plnkr.json b/public/docs/_examples/ngmodule/ts/plnkr.json index fabaf6a014..fbc92ce13b 100644 --- a/public/docs/_examples/ngmodule/ts/plnkr.json +++ b/public/docs/_examples/ngmodule/ts/plnkr.json @@ -8,19 +8,21 @@ "app/contact/contact.component.css", "app/contact/contact.component.html", + "app/contact/contact.service.ts", + "app/contact/contact.component.ts", "app/contact/contact.module.ts", "app/contact/contact.routing.ts", - "app/contact/contact.service.ts", "app/crisis/*.ts", - "app/hero/*.ts", + "app/hero/hero-detail.component.ts", + "app/hero/hero-list.component.ts", + "app/hero/hero.service.ts", - "!app/hero/hero.component.3.ts", - "!app/hero/hero.module.3.ts", - "!app/hero/hero.routing.3.ts", - "!app/hero/highlight.directive.ts", + "app/hero/hero.component.ts", + "app/hero/hero.module.ts", + "app/hero/hero.routing.ts", "app/core/*.css", "app/core/*.html", diff --git a/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json b/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json index dcdfb6e77f..6a7b39e2a2 100644 --- a/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json +++ b/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json @@ -11,21 +11,26 @@ "app/title.component.ts", "app/user.service.ts", - "app/contact/*.css", - "app/contact/*.html", - "app/contact/*.ts", + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.service.ts", - "!app/contact/contact.component.ts", - "!app/contact/contact.module.ts", - "!app/contact/contact.routing.ts", + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.3.ts", + "app/contact/contact.module.3.ts", + "app/contact/contact.routing.3.ts", + "app/contact/highlight.directive.ts", "app/crisis/*.ts", - "app/hero/*.ts", + "app/hero/hero-detail.component.ts", + "app/hero/hero-list.component.ts", + "app/hero/hero.service.ts", - "!app/hero/hero.component.ts", - "!app/hero/hero.module.ts", - "!app/hero/hero.routing.ts", + "app/hero/hero.component.3.ts", + "app/hero/hero.module.3.ts", + "app/hero/hero.routing.3.ts", + "app/hero/highlight.directive.ts", "styles.css", "index.3.html" diff --git a/public/docs/_examples/systemjs.config.plunker.build.js b/public/docs/_examples/systemjs.config.plunker.build.js index 3ccf77808c..a37e5a57f4 100644 --- a/public/docs/_examples/systemjs.config.plunker.build.js +++ b/public/docs/_examples/systemjs.config.plunker.build.js @@ -96,10 +96,3 @@ System.config(config); })(this); - - -/* -Copyright 2016 Google Inc. All Rights Reserved. -Use of this source code is governed by an MIT-style license that -can be found in the LICENSE file at http://angular.io/license -*/ diff --git a/public/docs/dart/latest/cookbook/_data.json b/public/docs/dart/latest/cookbook/_data.json index c7f07e9834..9ea1a5f8bf 100644 --- a/public/docs/dart/latest/cookbook/_data.json +++ b/public/docs/dart/latest/cookbook/_data.json @@ -12,6 +12,12 @@ "hide": true }, + "ngmodule-faq": { + "title": "Angular Module FAQs", + "intro": "Answers to frequently asked questions about @NgModule", + "hide": true + }, + "component-communication": { "title": "Component Interaction", "intro": "Share information between different directives and components" diff --git a/public/docs/dart/latest/cookbook/ngmodule-faq.jade b/public/docs/dart/latest/cookbook/ngmodule-faq.jade new file mode 100644 index 0000000000..6778b6af28 --- /dev/null +++ b/public/docs/dart/latest/cookbook/ngmodule-faq.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/js/latest/cookbook/_data.json b/public/docs/js/latest/cookbook/_data.json index a020c2e148..9a43659334 100644 --- a/public/docs/js/latest/cookbook/_data.json +++ b/public/docs/js/latest/cookbook/_data.json @@ -11,6 +11,12 @@ "intro": "Learn how Angular 1 concepts and techniques map to Angular 2" }, + "ngmodule-faq": { + "title": "Angular Module FAQs", + "intro": "Answers to frequently asked questions about @NgModule", + "hide": true + }, + "component-communication": { "title": "Component Interaction", "intro": "Share information between different directives and components" diff --git a/public/docs/js/latest/cookbook/ngmodule-faq.jade b/public/docs/js/latest/cookbook/ngmodule-faq.jade new file mode 100644 index 0000000000..6778b6af28 --- /dev/null +++ b/public/docs/js/latest/cookbook/ngmodule-faq.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index aea1b06b7c..f82d816cef 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -11,6 +11,11 @@ "intro": "Learn how Angular 1 concepts and techniques map to Angular 2" }, + "ngmodule-faq": { + "title": "Angular Module FAQs", + "intro": "Answers to frequently asked questions about @NgModule" + }, + "component-communication": { "title": "Component Interaction", "intro": "Share information between different directives and components" diff --git a/public/docs/ts/latest/cookbook/ngmodule-faq.jade b/public/docs/ts/latest/cookbook/ngmodule-faq.jade new file mode 100644 index 0000000000..b53208e402 --- /dev/null +++ b/public/docs/ts/latest/cookbook/ngmodule-faq.jade @@ -0,0 +1,1104 @@ +block includes + include ../_util-fns + +:marked + # FAQs + + **Angular Modules** help organize an application into cohesive blocks of functionality. + + The [Angular Modules chapter](../guide/ngmodule.html) covers the concepts and takes you step by step + from the most elementary `@NgModule` to a multi-faceted sample with lazy loaded modules. + + _This_ chapter answers the questions many developers ask about Angular Module design and implementation. +.alert.is-important + :marked + These FAQs assume that you have already read the [Angular Module](../guide/ngmodule.html) chapter. + +:marked + Declarations + * [What classes should I add to _declarations_?](#q-what-to-declare) + * [What is a _declarable_?](#q-declarable) + * [What classes should I *not* add to _declarations_?](#q-what-not-to-declare) + * [Why list the same component in multiple _NgModule_ properties?](#q-why-multiple-mentions) + * [What does "_Can't bind to 'x' since it isn't a known property of 'y'_" mean?](#q-why-cant-bind-to) + + Imports + * [What should I import?](#q-what-to-import) + * [Should I import _BrowserModule_ or _CommonModule_?](#q-browser-vs-common-module) + * [What if I import the same module twice?](#q-reimport) + + Exports + * [What should I export?](#q-what-to-export) + * [What should I *not* export?](#q-what-not-to-export) + * [Can I re-export imported classes and modules?](#q-re-export) + * [What is the _forRoot_ method?](#q-for-root) + + Service Providers + * [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) + * [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) + * [Should I add providers to the root _AppModule_ or the root _AppComponent_?](#q-root-component-or-module) + * [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) + * [How can I tell if a module or service was previously loaded?](#q-is-it-loaded) + + Entry Components + * [What is an _entry component_?](#q-entry-component-defined) + * [What is the difference between a _bootstrap_ component and an _entry component_?](#q-bootstrap_vs_entry_component) + * [When do I add components to _entryComponents_?](#q-when-entry-components) + * [Why does Angular need _entryComponents_?](#q-why-entry-components) + + General + * [What kinds of modules should I have and how should I use them?](#q-module-recommendations) + * [What's the difference between Angular and JavaScript Modules?](#q-ng-vs-js-modules) + * [What is a "template reference"?](#q-template-reference) + * [How does Angular find components, directives, and pipes in a template?](#q-template-reference) + * [What is the Angular Compiler?](#q-angular-compiler) + * [Can you summarize the _NgModule_ API?](#q-ngmodule-api) + +.l-hr + +a#q-what-to-declare +.l-main-section +:marked + ### What classes should I add to _declarations_? + + Add [declarable](#q-declarable) classes — components, directives, and pipes — to a `declarations` list. + + These classes must be declared in _exactly one_ module of the application. + Declare them in _this_ module if they _belong_ to this module. + +.l-hr + +a#q-declarable +.l-main-section +:marked + ### What is a _declarable_? + + _Declarables_ are the class types — components, directives, and pipes — + that you can add to a module's `declarations` list. + They're the _only_ classes that you can add to `declarations`. + +.l-hr + +a#q-what-not-to-declare +.l-main-section +:marked + ### What classes should I _not_ add to _declarations_? + + Only [declarable](#q-declarable) classes can be added to a module's `declarations` list. + + Do *not* declare + * a class that is already declared in another module, whether an app module, @angular module, or 3rd party module + + * an array of directives imported from another module. + For example, do not declare FORMS_DIRECTIVES from `@angular/forms`. + + * module classes + + * service classes + + * non-Angular classes and objects such as + strings, numbers, functions, entity models, configurations, business logic, and helper classes. + +.l-hr + +a#q-why-multiple-mentions +.l-main-section +:marked + ### Why list the same component in multiple _NgModule_ properties? + + We often see `AppComponent` listed in both `declarations` and `bootstrap`. + We might see `HeroComponent` listed in `declarations`, `exports`, and `entryComponents`. + + That _feels_ redundant but these properties have different functions + and we can't infer that membership in one list implies membership in another list. + + * `AppComponent` could be declared in this module but not bootstrapped. + * `AppComponent` could be bootstrapped in this module but declared in a different feature module. + * `HeroComponent` could be imported from another app module (so we can't declare it) and re-exported by this module. + * `HeroComponent` could be exported for inclusion in an external component's template and also dynamically loaded in a pop-up dialog. + +.l-hr + +a#q-why-cant-bind-to +.l-main-section +:marked + ### What does "_Can't bind to 'x' since it isn't a known property of 'y'_" mean? + + This error usually means either that you neglected to declare the directive "x" + or you haven't imported the module to which "x" belongs. + + For example, if "x" is `ngModel`, you probably haven't imported the `FormsModule` from `@angular/forms`. + + Perhaps you declared "x" in an application sub-module but forgot to export it? + The "x" class won't be visible to other modules until you add it to the `exports` list. + +.l-hr + +a#q-what-to-import +.l-main-section +:marked + ### What should I import? + + Import modules whose public (exported) [declarable classes](#q-declarable) + you need to reference in this module's component templates. + + This invariably means importing `CommonModule` from `@angular/common` for access to + the Angular directives such as `NgIf` and `NgFor`. + You can import it directly or from another module that [re-exports](#q-reexport) it. + + Import `FormsModule` from `@angular/forms` + if your components have `[(ngModel)]` two-way binding expressions. + + Import _shared_ and _feature_ modules when this module's components incorporate their + components, directives, and pipes. + + Only [import _BrowserModule_](#q-browser-vs-common-module) in the root `AppModule`. + +.l-hr + +a#q-browser-vs-common-module +.l-main-section +:marked + ### Should I import _BrowserModule_ or _CommonModule_? + + The **root application module** (`AppModule`) of almost every browser application + should import `BrowserModule` from `@angular/core`. + + `BrowserModule` provides services that are essential to launch and run a browser app. + + `BrowserModule` also re-exports `CommonModule` from `@angular/common` + which means that component in the `AppModule` module also have access to + the Angular directives every app needs such as `NgIf` and `NgFor`. + + _Do not import_ `BrowserModule` in any other module. + *Feature modules* and *lazy loaded modules* should import `CommonModule` instead. + They need the common directives. They don't need to re-install the app-wide providers. +.l-sub-section + :marked + `BrowserModule` throws an error if you try to lazy load a module that imports it. +:marked + Importing `CommonModule` also frees feature modules for use on _any_ target platform, not just browsers, + a fact of some interest to authors of cross-platform libraries. + +.l-hr +a#q-reimport +.l-main-section +:marked + ### What if I import the same module twice? + + That's not a problem. When three modules all import Module 'A', + Angular evaluates Module 'A' once, the first time it encounters it, and does not do so again. + + That's true at whatever level `A` appears in a hierarchy of imported modules. + When Module 'B' imports Module 'A', Module 'C' imports 'B', and Module 'D' imports `[C, B, A]`, + then 'D' triggers the evaluation of 'C' which triggers the evaluation of 'B' which evaluates 'A'. + When Angular gets to the 'B' and 'A' in 'D', they're already cached and ready to go. + + Angular does not like modules with circular references so don't let Module 'A' import Module 'B' which imports Module 'A'. + +.l-hr +a#q-what-to-export +.l-main-section +:marked + ### What should I export? + + Export [declarable](#q-declarable) classes that components in _other_ modules + should be able to reference in their templates. These are your _public_ classes. + If you don't export a class, it stays _private_, visible only to other component + declared in this module. + + You _can_ export any declarable class — components, directives, and pipes — + whether it is declared in this module or in an imported module. + + You _can_ re-export entire imported modules which effectively re-exports all of their exported classes. + A module can even export a module that it doesn't import. + +.l-hr + +a#q-what-not-to-export +.l-main-section +:marked + ### What should I *not* export? + + Do *not* export + + * Private components, directives, and pipes that you need only within components declared in this module. + If you don't want another module to see it, don't export it. + + * Non-declarable objects such as services, functions, configurations, entity models, etc. + + * Components that are only loaded dynamically by the router or by bootstrapping. + Such [entry components](#q-entry-component-defined) can never be selected in another component's template. + There's no harm in exporting them but no benefit either. + + * Pure service modules that don't have public (exported) declarations. + For example, there is no point in re-exporting `HttpModule` because it doesn't export anything. + It's only purpose is to add http service providers to the application as a whole. + +.l-hr + +a#q-reexport +a#q-re-export +.l-main-section +:marked + ### Can I re-export classes and modules? + + Absolutely! + + Modules are a great way to selectively aggregate classes from other modules and + re-export them in a consolidated, convenience module. + + A module can re-export entire modules which effectively re-exports all of their exported classes. + Angular's own `BrowserModule` exports a couple of modules like this: +code-example. + exports: [CommonModule, ApplicationModule] + +:marked + A module can export a combination of its own declarations, selected imported classes, and imported modules. +.l-sub-section + :marked + Don't bother re-exporting pure service modules. + Pure service modules don't export [declarable](#q-declarable) classes that another module could use. + For example, there is no point in re-exporting `HttpModule` because it doesn't export anything. + It's only purpose is to add http service providers to the application as a whole. + +.l-hr + +a#q-for-root +.l-main-section +:marked + ### What is the _forRoot_ method? + + The `forRoot` static method is a convention that makes it easy for developers to configure the module's provider(s). + + The `RouterModule.forRoot` method is a good example. + Apps pass a `Routes` object to `RouterModule.forRoot` in order to configure the app-wide `Router` service with routes. + `RouterModule.forRoot` returns a [ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html). + We add that result to the `imports` list of the root `AppModule`. + +.alert.is-important + :marked + Only call and import a `.forRoot` result in the root application module, `AppModule`. + Importing it in any other module, particularly in a lazy loaded module, + is contrary to the intent and is likely to produce a runtime error. +:marked + `RouterModule` also offers a `forChild` static method for configuring the routes of lazy loaded modules. + + **_forRoot_** and **_forChild_** are conventional names for methods that + configure services in root and feature modules respectively. + + Angular doesn't recognize these names but Angular developers do. + Follow this convention when you write similar modules with configurable service providers. + +.l-hr + +a#q-module-provider-visibility +.l-main-section +:marked + ### Why is a service provided in a feature module visible everywhere? + + Providers listed in the `@NgModule.providers` of a bootstrapped module have **application scope**. + Adding a service provider to `@NgModule.providers` effectively publishes the service to the entire application. + + When we import a module, + Angular adds the module's service providers (the contents of its `providers` list) + to the application _root injector_. + + This makes the provider visible to every class in the application that knows the provider's lookup token. + + This is by design. + Extensibility through module imports is a primary goal of the Angular module system. + Merging module providers into the application injector + makes it easy for a module library to enrich the entire application with new services. + By adding the `HttpModule` once, every application component can make http requests. + + However, this can feel like an unwelcome surprise if you are expecting the module's services + to be visible only to the components declared by that feature module. + If the `HeroModule` provides the `HeroService` and the root `AppModule` imports `HeroModule`, + any class that knows the `HeroService` _type_ can inject that service, + not just the classes declared in the `HeroModule`. + +.l-hr + +a#q-lazy-loaded-module-provider-visibility +.l-main-section +:marked + ### Why is a service provided in a lazy loaded module visible only to that module? + + Unlike providers of the modules loaded at launch, + providers of lazy loaded modules are *module-scoped*. + + When the Angular router lazy-loads a module, it creates a new execution context. + That [context has its own injector](#q-why-child-injector "Why Angular creates a child injector") which is a direct child of the application injector. + + The router adds the lazy module's providers and the providers of its imported modules to this child injector. + + These providers are insulated from changes to application providers with the same lookup token. + 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. + +.l-hr +a#q-module-provider-duplicates +.l-main-section +:marked + ### What if two modules provide the _same_ service? + + When two imported modules, loaded at the same time, list a provider with the same token, + the second module's provider "wins". That's because both providers are added to the same injector. + + When Angular looks to inject a service for that token, + it creates and delivers the instance created by the second provider. + + _Every_ class that injects this service gets the instance created by the second provider. + Even classes declared within the first module get the instance created by the second provider. + _This can be an unwelcome surprise_. + + If Module A provides a service for token 'X' and imports a module B + that also provides a service for token 'X', then Module A's service definition "wins". + + The service provided by the root `AppModule` takes precedence over services provided by imported modules. + The `AppModule` always wins. + +.l-hr + +a#q-component-scoped-providers +.l-main-section +:marked + ### How do I restrict service scope to a module? + + When a module is loaded at application launch, + its `@NgModule.providers` have ***application-wide scope***. + They are available for injection throughout the application. + + Imported providers are easily replaced by providers from another imported module. + Such replacement may be by design. It could be unintentional and have adverse consequences. + +.alert.is-important + :marked + As a general rule, import modules with providers _exactly once_, preferably in the application's _root module_. + That's also usually the best place to configure, wrap, and override them. + +:marked + Suppose a module requires a customized `HttpBackend` that adds a special header for all Http requests. + If another module elsewhere in the application also customizes `HttpBackend` + or merely imports the `HttpModule`, it could override this module's `HttpBackend` provider, + losing the special header. The server will reject http requests from this module. + +.alert.is-important + :marked + Avoid this problem by importing the `HttpModule` only in the `AppModule`, the application _root module_. + +:marked + If you must guard against this kind of "provider corruption", *don't rely on a launch-time module's `providers`.* + + Load the module lazily if you can. + Angular gives a [lazy-loaded module](#q-lazy-loaded-module-provider-visibility) its own child injector. + The module's providers are visible only within the component tree created with this injector. + + If you must load the module eagerly, when the application starts, + ***provide the service in a component instead.*** + + Continuing with the same example, suppose the components of a module truly require a private, custom `HttpBackend`. + + Create a "top component" that acts as the root for all of the module's components. + Add the custom `HttpBackend` provider to the top component's `providers` list rather than the module's `providers`. + Recall that Angular creates a child injector for each component instance and populates the injector + with the component's own providers. + + When a child of this component _asks_ for the `HttpBackend` service, + Angular provides the local `HttpBackend` service, + not the version provided in the application root injector. + Child components will make proper http requests no matter what other modules do to `HttpBackend`. + + Be sure to create module components as children of this module's top component. + + You can embed the child components in the top component's template. + Alternatively, make the top component a routing host by giving it a ``. + Define child routes and let the router load module components into that outlet. + +.l-hr + +a#q-root-component-or-module +.l-main-section +:marked + ### Should I add providers to the root _AppModule_ or the root _AppComponent_? + + Most apps launch with an initial set of service providers. + Should we register those providers on the root `AppModule` (`@NgModule.providers`) or + the root `AppComponent` (`@Component.providers`)? + + **_List such providers in the root_ `AppModule` _unless you have a compelling reason to do otherwise_**. + + Angular registers all startup module providers with the application root injector. + The services created from root injector providers are available to the entire application. + They are _application-scoped_. + + 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. + `AppComponent`services are available to that component and its component tree. + They are _component-scoped_. + + The `AppComponent`'s injector is a _child_ of the root injector, one down in the injector hierarchy. + That is _almost_ the entire application for apps that don't use the router. + But "almost" isn't good enough for routed applications. + + `AppComponent` services don't exist at the root level where routing operates. + Lazy loaded modules can't reach them. + In this sample applications, if we had registered `UserService` in the `AppComponent`, + the `HeroComponent` couldn't inject it. + 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. + We _should_ register a service in `AppComponent` providers if the service must be hidden + from components outside the `AppComponent` tree. + + These are special cases. + When in doubt, register with the `AppModule`. + +.l-hr + +a#q-why-bad +.l-main-section +:marked + ### Why is it bad if _SharedModule_ provides a service to a lazy loaded module? + + This question arose in the [Angular Module](../guide/ngmodule.html#no-shared-module-providers) chapter + when we discussed the importance of keeping providers out of the `SharedModule`. + + Suppose we had listed the `UserService` in the module's `providers` (which we did not). + Suppose every module imports this `SharedModule` (which they all do). + + When the app starts, Angular eagerly loads the `AppModule` and the `ContactModule`. + + Both instances of the imported `SharedModule` would provide the `UserService`. + Angular registers one of them in the root app injector (see [above](#q-reimport)). + Then some component injects `UserService`, Angular finds it in the app root injector, + and delivers the app-wide singleton `UserService`. No problem. + + Now consider the `HeroModule` _which is lazy loaded!_ + + When the router lazy loads the `HeroModule`, it creates a child injector and registers the `UserService` + provider with that child injector. The child injector is _not_ the root injector. + + When Angular creates a lazy `HeroComponent`, it must inject a `UserService`. + This time it finds a `UserService` provider in the lazy module's _child injector_ + and creates a _new_ instance of the `UserService`. + This is an entirely different `UserService` instance + than the app-wide singleton version that Angular injected in one of the eagerly loaded components. + + That's almost certainly a mistake. +.l-sub-section + :marked + Prove it for yourself. + Run the live example. + Modify the `SharedModule` so that it provides the `UserService` rather than the `CoreModule`. + Then toggle between the "Contact" and "Heroes" links a few times. + The username goes bonkers as the Angular creates a new `UserService` instance each time. + +.l-hr + +a#q-why-child-injector +.l-main-section +:marked + ### Why does lazy loading create a child injector? + + Angular adds `@NgModule.providers` to the application root injector ... unless the module is lazy loaded. + Then it creates a _child injector_ and adds the module's providers to the child injector. + + This means that a module behaves differently depending on whether it is loaded during application start + or lazy loaded later. Neglecting that difference can lead to [adverse consequences](#q-why-bad). + + Why doesn't Angular add lazy loaded providers to the app root injector as it does for eagerly loaded modules? + Why the inconsistency? + + The answer is grounded in a fundamental characteristic of the Angular dependency injection system. + An injector can add providers _until it is first used_. + Once an injector starts creating and delivering services, its provider list is frozen. No new providers allowed. + + When an applications starts, Angular first configures the root injector with the providers of all eagerly loaded modules + _before_ creating its first component and injecting any of the provided services. + Once the application begins, the app root injector is closed to new providers. + + Time passes. Application logic triggers lazy loading of a module. + Angular must add the lazy loaded module's providers to an injector _somewhere_. + It can't added them to the app root injector because that injector is closed to new providers. + So Angular creates a new child injector for the lazy loaded module context. + +.l-hr + +a#q-is-it-loaded +.l-main-section +:marked + ### How can I tell if a module or service was previously loaded? + + Some modules and its services should only be loaded once by the root `AppModule`. + Importing the module a second time by lazy loading a module could [produce errant behavior](#q-why-bad) + that may be difficult to detect and diagnose. + + We can guard against that danger by writing a constructor that attempts to inject the module or service + from the root app injector. If the injection succeeds, the class has been loaded a second time. + We can throw an error or take other remedial action. + + Certain Angular modules (such as `BrowserModule`) implements such a guard + as does this Angular Module chapter sample's `CoreModule` constructor. ++makeExample('ngmodule/ts/app/core/core.module.ts', 'ctor', 'app/core/core.module.ts (Constructor)')(format='.') +:marked + +.l-hr + +a#q-entry-component-defined +.l-main-section +:marked + ### What is an _entry component_? + + Any component that Angular loads _imperatively_ by type is an _entry component_, + + A component loaded _declaratively_ via its selector is _not_ an entry component. + + Most application components are loaded declaratively. + Angular uses the component's selector to locate the element in the template. + It then creates the HTML representation of the component and inserts it into the DOM at the selected element. + These are not entry components. + + A few components are only loaded dynamically and are _never_ referenced in a component template. + + The bootstrapped root `AppComponent` is an _entry component_. + True, its selector matches an element tag in `index.html`. + But `index.html` is not a component template and the `AppComponent` + selector doesn't match an element in any component template. + + Angular loads `AppComponent` dynamically either because we listed it _by type_ in `@NgModule.bootstrap` + or because we boostrapped it imperatively with the module's `ngDoBootstrap` method. + + Components in route definitions are also _entry components_. + A route definition refers to a component by its _type_. + The router ignores a routed component's selector (if it even has one) and + loads the component dynamically into a `RouterOutlet`. + + The compiler can't discover these _entry components_ by looking for them in other component templates. + We must tell it about them ... by adding them to the `entryComponents` list. + + Angular automatically adds two kinds of components to the module's `entryComponents`: + 1. the component in the `@NgModule.bootstrap` list + 1. components referenced in router configuration + + We don't have to mention these components explicitly although it does not harm to do so. + +.l-hr + +a#q-bootstrap_vs_entry_component +.l-main-section +:marked + ### What's the difference between a _bootstrap_ component and an _entry component_? + + A bootstrapped component _is_ an [entry component](#q-entry-component-defined). + It's an entry component that Angular loads into the DOM during the bootstrap (application launch) process. + Other entry components are loaded dynamically by other means such as with the router. + + The `@NgModule.bootstrap` property tells the compiler _both_ that this is an entry component _and_ + that it should generate code to bootstrap the application with this component. + + There is no need to list a component in both the `bootstrap` and `entryComponent` lists + although it is harmless to do so. + +.l-hr + +a#q-when-entry-components +.l-main-section +:marked + ### When do I add components to _entryComponents_? + + Most application developers won't need to add components to the `entryComponents`. + + Angular adds certain components to _entry components_ automatically. + Components listed in `@NgModule.bootstrap` are added automatically. + Components referenced in router configuration are added automatically. + These two mechanisms account for almost all entry components. + + If your app happens to bootstrap or dynamically load a component _by type_ in some other manner, + you'll have to add it to `entryComponents` explicitly. + + Although it's harmless to add components to this list, + it's best to add only the components that are truly _entry components_. + Don't include components that [are referenced](#q-template-reference) + in the templates of other components. + +.l-hr + +a#q-why-entry-components +.l-main-section +:marked + ### Why does Angular need _entryComponents_? + _Entry components_ are also declared. + Why doesn't the Angular compiler generate code for every component in `@NgModule.declarations`? + Then we wouldn't need entry components. + + The reason is _tree shaking_. For production apps we want to load the smallest, fastest code possible. + The code should contain only the classes that we actually need. + It should exclude a component that's never used, whether or not that component is declared. + + In fact, many libraries declare and export components we'll never use. + The _tree shaker_ will drop these components from the final code package + if we don't reference them. + + If the [Angular compiler](#q-angular-compiler) generated code for every declared component, + it would defeat the purpose of the tree shaker. + + Instead, the compiler adopts a recursive strategy that generates code only for the components we use. + + It starts with the entry components, + then it generates code for the declared components it [finds](#q-template-reference) in an entry component's template, + then for the declared components it discovers in the templates of previously compiled components, + and so on. At the end of the process, it has generated code for every entry component + and every component reachable from an entry component. + + If a component isn't an _entry component_ or wasn't found in a template, + the compiler omits it. + + +.l-hr + +a#q-module-recommendations +.l-main-section +:marked + #### What kinds of modules should I have and how should I use them? + + Every app is different and developers have varying levels of experience and comfort with the available choices. + Some suggestions and guidelines appear to have wide appeal. + +.alert.is-important + :marked + The following is preliminary guidance based on early experience using Angular modules in a few applications. + Read with appropriate caution and reflection. + +:marked + #### _SharedModule_ + Create a `SharedModule` with the components, directives, and pipes that you use + everywhere in your app. This module should consist entirely of `declarations` + most of them exported. + + It may re-export other [widget modules](#widget-feature-module) such as `CommonModule`, + `FormsModule` and modules with the UI controls that you use most widely. + + It should ***not*** have `providers` for reasons [explained earlier](#q-why-bad). + Nor should any of its imported or re-exported modules have `providers`. + Know what you're doing and why if you deviate from this guideline. + + Import the `SharedModule` in your _feature_ modules, + both those loaded when the app starts and those you lazy load later. + + #### _CoreModule_ + Create a `CoreModule` with `providers` for the singleton services you load when the application starts. + + Import `CoreModule` in the root `AppModule` only. + Never import `CoreModule` in any module other than the root `AppModule`. + + Consider making `CoreModule` a [pure services module](#service-feature-module) with no `declarations`. + +.l-sub-section + :marked + This chapter sample departs from that advice by declaring and exporting two components that are + only used within the root `AppComponent` declared by `AppModule`. + Someone following this guideline strictly would have declared these components in the `AppModule` instead. + +:marked + #### Feature Modules + Create _Feature Modules_ around specific application business domains, user workflows, and utility collections. + + Feature modules tend to fall into one of these four groups: + * [Domain Feature Modules](#domain-feature-module) + * [Routed Feature Modules](#routed-feature-module) + * [Service Feature Modules](#service-feature-module) + * [Widget Feature Modules](#widget-feature-module) + +.l-sub-section + :marked + Real world modules are often hybrids that knowingly deviate from the following guidelines. + They are guidelines, not laws. + Follow them until you have a good reason to do otherwise. + +table + tr + th(style="vertical-align: top") Feature Module + th(style="vertical-align: top") Guidelines + tr + td(style="vertical-align: top")Domain + td + :marked + Domain Feature Modules deliver a user experience **dedicated to a particular application domain** + like editing a customer or placing an order. + + They typically have a top component that acts as the feature root. + Private, supporting sub-components descend from it. + + Domain feature module consist mostly of _declarations_. + Only the top component is exported. + + Domain feature modules rarely have _providers_. + When they do, the lifetime of the provided services + should be the same as the lifetime of the module. + + Do not provide application-wide singleton services in a domain feature module. + + Domain feature modules are typically imported _exactly once_ by a larger feature module. + + They might be imported by the root `AppModule` of a small application that lacks routing. + + .l-sub-section + :marked + For an example, see [_ContactModule_](../guide/ngmodule.html#contact-module-v1) + in the Angular Module chapter, before we introduced routing. + tr + td(style="vertical-align: top")Routed + td + :marked + _Routed Feature Modules_ are _Domain Feature modules_ + whose top components are the **targets of router navigation routes**. + + All lazy loaded modules are routed feature modules by nature. + + This chapter's `ContactModule`, `HeroModule` and `CrisisModule` are routed feature modules. + + Routed Feature Modules _should not export anything_. + They don't have to because none of their components ever appear in the template of an external component. + + Routed Feature Modules are _never imported_. + + Routed Feature Modules rarely have _providers_ for reasons [explained earlier](#q-why-bad). + When they do, the lifetime of the provided services + should be the same as the lifetime of the module. + + Do not provide application-wide singleton services in a routed feature module + or in a module that the routed module imports. + + tr + td(style="vertical-align: top")Service + td + :marked + _Service Modules_ **provide utility services** such as data access and messaging. + + Ideally they consist entirely of _providers_ and have no _declarations_. + The `CoreModule` and Angular's `HttpModule` are good examples. + + Service Modules should _only_ be imported by the root `AppModule`. + + Do **not** import them in other feature modules. + Know what you're doing and why if you deviate from this guideline. + tr + td(style="vertical-align: top")Widget + td + :marked + A _Widget Module_ makes **components, directives, and pipes** available to external modules. + + `CommonModule` and `SharedModule` are widget modules. + Many third party UI component libraries are widget modules. + + A Widget Module should consist entirely of _declarations_, most of them exported. + + A Widget Module should rarely have _providers_. + Know what you're doing and why if you deviate from this guideline. + + Import Widget Modules in any module whose component templates need the widgets. + +:marked + The following table summarizes the key characteristics of each _Feature Module_ group. +.l-sub-section + :marked + Real world modules are often hybrids that knowingly deviate from these guidelines. +table + tr + th Feature Module + th Declarations + th Providers + th Exports + th Imported By + th Examples + tr + td Domain + td Yes + td Rare + td Top Component + td Feature, AppModule + td ContactModule (before routing) + tr + td Routed + td Yes + td Rare + td No + td Nobody + td ContactModule, HeroModule, CrisisModule + tr + td Service + td No + td Yes + td No + td AppModule + td HttpModule, CoreModule + tr + td Widget + td Yes + td Rare + td Yes + td Feature + td CommonModule, SharedModule + +.l-hr + +a#q-ng-vs-js-modules +.l-main-section +:marked + ### What's the difference between Angular and JavaScript Modules? + + Angular and JavaScript are two different yet complementary module systems. + + In modern JavaScript, [every file is a _module_](http://exploringjs.com/es6/ch_modules.html). + Within each file we write an `export` statement to make parts of the module public: + +code-example(format='.'). + export class AppComponent { ... } + +:marked + Then we `import` a part in another module: + +code-example(format='.'). + import { AppComponent } from './app.component'; + +:marked + This kind of modularity is a feature of the _JavaScript language_. + + An _Angular Module_ is a feature of _Angular_ itself. + + Angular's `NgModule` also has `imports` and `exports` and they serve a similar purpose. + + We _import_ other Angular modules so we can use their exported classes in component templates. + We _export_ this Angular module's classes so they can be imported and used by components of _other_ modules. + + The Angular module classes differ from JavaScript module class in three key respects: + + 1. An Angular module bounds [_declarable classes_](#q-declarables) only. + Declarables are the only classes that matter to the [Angular compiler](#q-angular-compiler). + + 1. Instead of defining all member classes in one giant file (as in a JavaScript module), + we list the module's classes in the `@NgModule.declarations` list. + + 1. An Angular module can only export the [_declarable classes_](#q-declarables) + it owns or imports from other modules. + It doesn't declare or export any other kind of class. + + The Angular Module is also special in another way. + Unlike JavaScript modules, an Angular module can extend the _entire_ application with services + by adding providers to the `@NgModule.providers` list. + +.alert.is-important + :marked + The provided services do not belong to the module nor are they scoped to the declared classes. + They are available _everywhere_. + +:marked + Here's an _Angular Module_ class with imports, exports, and declarations. ++makeExample('ngmodule/ts/app/contact/contact.module.2.ts', 'class')(format=".") +:marked + Of course we use _JavaScript_ modules to write _Angular_ modules as seen in the complete `contact.module.ts` file: ++makeExample('ngmodule/ts/app/contact/contact.module.2.ts', '', 'app/contact/contact.module.ts')(format=".") + +.l-hr + +a#q-template-reference +.l-main-section +h4. + How does Angular find components, directives, and pipes in a template?
What is a template reference? +:marked + The [Angular compiler](#q-angular-compiler) looks inside component templates + for other components, directives, and pipes. When it finds one, that's a "template reference". + + The Angular compiler finds a component or directive in a template when it can match the **selector** of that + component or directive to some HTML in that template. + + The compiler finds a pipe if the pipe's **name** appears within the pipe syntax of the template HTML. + + Angular only matches selectors and pipe names for classes that are declared by this module + or exported by a module that this module imports. + +.l-hr + +a#q-angular-compiler +.l-main-section +:marked + ### What is the Angular Compiler? + + The _Angular Compiler_ converts the application code we write into highly performant JavaScript code. + The `@NgModule` metadata play an important role in guiding the compilation process. + + The code we write is not immediately executable. + Consider **components**. + Components have templates that contain custom elements, attribute directives, Angular binding declarations, + and some peculiar syntax that clearly isn't native HTML. + + The _Angular Compiler_ reads the template markup, + combines it with the corresponding component class code, and emits _component factories_. + + A component factory creates a pure, 100% JavaScript representation + of the component that incorporates everything described in its `@Component` metadata: + the HTML, the binding instructions, the attached styles ... everything. + + Because **directives** and **pipes** appear in component templates, + the _Angular Compiler_ incorporates them into compiled component code too. + + `@NgModule` metadata tells the _Angular Compiler_ what components to compile for this module and + how to link this module with other modules. + +.l-hr + +a#q-ngmodule-api +.l-main-section +:marked + ## *NgModule* API + + The following chart summarizes the `NgModule` metadata properties. +// + export interface NgModuleMetadataType { + providers?: any[]; + declarations?: Array; + imports?: Array; + exports?: Array; + entryComponents?: Array; + bootstrap?: Array; + schemas?: Array; + } + +table + tr + th Property + th Description + tr + td(style="vertical-align: top") declarations + td + :marked + A list of [declarable](#q-declarables) classes, + the **component**, **directive** and **pipe** classes that _belong to this module_. + + These declared classes are visible within the module but invisible to + components in a different module unless (a) they are _exported_ from this module and + (b) that other module _imports_ this one. + + Components, directives and pipes must belong to _exactly_ one module. + The compiler emits an error if we try to declare the same class in more than one module. + + **Do not re-declare a class imported from another module.** + + tr + td(style="vertical-align: top") providers + td + :marked + A list of dependency injection providers. + + Angular registers these providers with the root injector of the module's execution context. + That's the application's root injector for all modules loaded when the application starts. + + Angular can inject one of these provider services into any component in the application. + If this module provides the `HeroService`, or any module loaded at launch provides the `HeroService`, + Angular can inject the same `HeroService` intance into any app component. + + A lazy loaded module has its own sub-root injector which typically + is a direct child of the application root injector. + + Lazy loaded services are scoped to the lazy module's injector. + If a lazy loaded module also provides the `HeroService`, + any component created within that module's context (e.g., 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. + + tr + td(style="vertical-align: top") imports + td + :marked + A list of supporting modules. + + Specifically, the list of modules whose exported components, directives or pipes + are referenced by the component templates declared in this module. + + A component template can [reference](#q-template-reference) another component, directive or pipe + on two conditions: either the referenced class is declared in this module + or the class was imported from another module. + + A component can use the `NgIf` and `NgFor` directives only because its parent module + imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`). + + We can import many standard directives with the `CommonModule`. + But some familiar directives belong to other modules. + A component template can bind with `[(ngModel)]` only after importing the Angular `FormsModule`. + tr + td(style="vertical-align: top") exports + td + :marked + A list of declarations — **component**, **directive**, and **pipe** classes — that + an importing module can use. + + Exported declarations are the module's _public API_. + A component in another module can [reference](#q-template-reference) _this_ module's `HeroComponent` + if (a) it imports this module and (b) this module exports `HeroComponent`. + + Declarations are private by default. + If this module does _not_ export `HeroComponent`, no other module can see it. + + Importing a module does _not_ automatically re-export the imported module's exports. + Module 'B' can't use `ngIf` just because it imported module `A` which imported `CommonModule`. + Module 'B' must import `CommonModule` itself. + + A module can list another module among its `exports` in which case + all of that module's public components, directives, and pipes are exported. + + [Re-export](#q-re-export) makes module transitivity explicit. + If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', + Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. + + tr + td(style="vertical-align: top") bootstrap + td + :marked + A list of components that can be bootstrapped. + + Usually there is only one component in this list, the _root component_ of the application. + + Angular can launch with multiple bootstrap components, + each with its own location in the host web page. + + A bootstrap component is automatically an `entryComponent` + + tr + td(style="vertical-align: top") entryComponents + td + :marked + A list of components that are _not_ [referenced](#q-template-reference) in a reachable component template. + + Most developers will never set this property. Here's why. + + The [_Angular Compiler_](#q-angular-compiler) must know about every component actually used in the application. + The compiler can discover most components by walking the tree of references + from one component template to another. + + But there's always at least one component that is not referenced in any template: + the root component, `AppComponent`, that we bootstrap to launch the app. + That's why it's called an _entry component_. + + Routed components are also _entry components_ because they aren't referenced in a template either. + The router creates them and drops them into the DOM near a ``. + + While the bootstrapped and routed components are _entry components_, + we usally don't have to add them to a module's `entryComponents` list. + + Angular automatically adds components in the module's `bootstrap` list to the `entryComponents` list. + The `RouterModule` adds routed components to that list. + + That leaves only two sources of undiscoverable components. + 1. Components bootstrapped using one of the imperative techniques. + 1. Components dynamically loaded into the DOM by some means other than the router. + + Both are advanced techniques that few developers will ever employ. + If you are one of those few, you'll have to add these components to the + `entryComponents` list yourself, either programmatically or by hand. diff --git a/public/docs/ts/latest/guide/ngmodule.jade b/public/docs/ts/latest/guide/ngmodule.jade index 49e8d11c74..0239e5f62d 100644 --- a/public/docs/ts/latest/guide/ngmodule.jade +++ b/public/docs/ts/latest/guide/ngmodule.jade @@ -3,7 +3,6 @@ block includes // TODO Images - Confirm plunkers :marked **Angular Modules** help organize an application into cohesive blocks of functionality. @@ -11,7 +10,7 @@ block includes An Angular Module _class_ is adorned with the **NgModule** decorator that defines metadata about the module. This chapter explains how to **create** `NgModule` classes and how to load them, - either immediately when the application launches or later, as needed, via the Router. + either immediately when the application launches or later, as needed, via the [Router](router.html). ## Contents * [Angular modularity](#angular-modularity "Add structure to the app with NgModule") @@ -28,7 +27,6 @@ block includes * [Configure core services with _forRoot_](#core-for-root "Configure providers during module import") * [Prevent reimport of the _CoreModule_](#prevent-reimport "because bad things happen if a lazy loaded module imports Core") * [NgModule metadata properties](#ngmodule-properties "A technical summary of the @NgModule metadata properties") - * [FAQ](#faq "Frequently asked questions") ### Live examples This chapter explains Angular Modules through a progression of improvements to a sample with a "Tour of Heroes" theme. @@ -40,6 +38,14 @@ block includes * Just before adding _SharedModule_ * The final version + ### Frequently Asked Questions (FAQs) + + This chapter covers Angular Module concepts in a tutorial fashion. + + The companion [Angular Module FAQs](../cookbook/ngmodule-faq.html "Angular Module FAQs") cookbook + offers ready answers to specific design and implementation questions. + Read this chapter first before hopping over to those FAQs. + .l-hr a#angular-modularity @@ -124,7 +130,7 @@ a#bootstrap In this chapter we consider two options, both targeting the browser. ### Dynamic bootstrapping with the Just-In-Time (JIT) compiler - In the first, _dynamic_ option, the [Angular compiler](#q-angular-compiler "About the Angular Compiler") + In the first, _dynamic_ option, the [Angular compiler](../cookbook/ngmodule-faq.html#q-angular-compiler "About the Angular Compiler") compiles the application in the browser and then launches the app. +makeExample('ngmodule/ts/app/main.ts', '', 'app/main.ts (dynamic)')(format=".") @@ -178,10 +184,9 @@ a#declarations We update the `AppComponent` template to attach the directive to the title: +makeExample('ngmodule/ts/app/app.component.1.ts', 'template')(format=".") :marked - If we ran the app now, Angular would report an error in the console because - it doesn't recognize the `highlight` binding. - + If we ran the app now, Angular would not recognize the `highlight` attribute and would ignore it. We must declare the directive in `AppModule`. + Import the `HighlightDirective` class and add it to the module's `declarations` like this: +makeExample('ngmodule/ts/app/app.module.1.ts', 'directive')(format=".") @@ -262,8 +267,7 @@ a#imports `CommonModule` contributes many of the common directives that applications need including `ngIf` and `ngFor`. - `BrowserModule` imports `CommonModule` and _re-exports_ it. - We'll cover re-exporting a module [later](#q-re-export) in the chapter. + `BrowserModule` imports `CommonModule` and [_re-exports_](../cookbook/ngmodule-faq.html#q-re-export) it. The net effect is that an importer of `BrowserModule` gets `CommonModule` directives automatically. :marked Many familiar Angular directives do not belong to`CommonModule`. @@ -308,7 +312,7 @@ a#imports and break the component into three constituent HTML, TypeScript, and css files: +makeTabs( `ngmodule/ts/app/contact/contact.component.html, - ngmodule/ts/app/contact/contact.component.ts, + ngmodule/ts/app/contact/contact.component.3.ts, ngmodule/ts/app/contact/contact.component.css, ngmodule/ts/app/contact/contact.service.ts, ngmodule/ts/app/contact/awesome.pipe.ts, @@ -339,7 +343,9 @@ a#imports Add the `FormsModule` to the `AppModule` metadata's `imports` list. +makeExample('ngmodule/ts/app/app.module.1.ts', 'imports')(format=".") :marked - Now `[(ngModel)]` binding works and the user input is validated by Angular Forms. + Now `[(ngModel)]` binding will work and the user input will be validated by Angular Forms, + once we declare our new component, pipe and directive. + .alert.is-critical :marked **Do not** add `NgModel` — or the `FORMS_DIRECTIVES` — @@ -407,7 +413,8 @@ a#application-scoped-providers To inject `ContactService`, you must first import its _type_. Only Contact components should import the `ContactService` _type_. - [An FAQ below](#q-component-scoped-providers) pursues this issue and its mitigations in greater detail. + See the [FAQ that pursues this issue](../cookbook/ngmodule-faq.html#q-component-scoped-providers) + and its mitigations in greater detail. :marked ### Run the app @@ -431,7 +438,8 @@ a#application-scoped-providers .file highlight.directive.ts :marked - Try the live example. + Try the example: + a#resolve-conflicts .l-main-section @@ -495,9 +503,6 @@ a#feature-modules The `HighlightDirective` in contact is re-coloring the work done by the `HighlightDirective` declared in `AppModule`. And it's coloring the application title text when it should only color the `ContactComponent`. - * A change to a contact class could break an application part in some unrelated section of the app. - The app is brittle and hard to test. - * The app lacks clear boundaries between contact functionality and other application features. That lack of clarity makes it harder to assign development responsibilities to different teams. @@ -522,7 +527,7 @@ a#feature-modules Otherwise, a feature module is distinguished primarily by its intent. - A feature module delivers a cohesive set of functionality. + A feature module delivers a cohesive set of functionality focused on an application business domain, a user workflow, a facility (forms, http, routing), or a collection of related utilities. @@ -560,11 +565,11 @@ a#feature-modules .alert.is-important :marked Modules do not inherit access to the components, directives or pipes that are declared in other modules. - The fact that `AppModule` imports `FormsModule` is irrelevant. - The `ContactModule` must import `FormsModule` explicitly so that - `ContactComponent` can data bind with `ngModel`. + What `AppModule` imports is irrelevant to `ContactModule` and vice versa. + Before `ContactComponent` can bind with `[(ngModel)]`, its `ContactModule` must import `FormsModule`. :marked - We also replaced `BrowserModule` by `CommonModule` for reasons explained [below](#q-browser-vs-common-module). + We also replaced `BrowserModule` by `CommonModule` for reasons explained in + [an FAQ](../cookbook/ngmodule-faq.html#q-browser-vs-common-module). We _declare_ the contact component, directive, and pipe in the module `declarations`. @@ -606,6 +611,8 @@ a#feature-modules * No `ContactService` provider * No `HighlightDirective` conflict + Try this `ContactModule` version of the sample. + Try the live example. a#lazy-load @@ -673,17 +680,19 @@ a#lazy-load +makeExample('ngmodule/ts/app/app.routing.ts', 'lazy-routes')(format='.') .l-sub-section :marked - Note that the module location is a _string_, not a _type_. + Note that the lazy loaded module location is a _string_, not a _type_. + + To reference the _type_ we'd have to use a JavaScript import statement to get the module symbol, + which loads the module immediately, defeating our intent to load the module later. - To reference the _type_ we'd have to import the module, which loads the module immediately, - defeating our intent to load the module later. A string, on the other hand, is just a string. It has no side-effects. :marked The module location strings in this app identify module _files_, not module _classes_. That works because each module class is marked as the default export in its file. +makeExample('ngmodule/ts/app/crisis/crisis.module.ts', 'export-default', '/app/crisis/crisis.module.ts (export default)')(format='.') :marked - _Remember to use_ `export default`_, not just_ `export`. + _Remember to use_ `export default`_ for the lazy loaded module class. + Continue to use `export` for all other classes. :marked ### RouterModule.forRoot @@ -723,8 +732,8 @@ a#lazy-load deliver different `import` values to root and feature modules. Angular doesn't recognize them but Angular developers do. - [Follow this convention](#q-for-root) if you write a similar module - that has both shared [_declarables_](#q-declarable) and services. + [Follow this convention](../cookbook/ngmodule-faq.html#q-for-root) if you write a similar module + that has both shared [_declarables_](../cookbook/ngmodule-faq.html#q-declarable) and services. :marked `ContactModule` has changed in two small but important details @@ -845,12 +854,13 @@ a#shared-module `UserService` is an application-wide singleton. We don't want each module to have its own separate instance. - Yet there is [a real danger](#q-why-it-is-bad) of that happening + Yet there is [a real danger](../cookbook/ngmodule-faq.html#q-why-it-is-bad) of that happening if the `SharedModule` provides the `UserService`. .alert.is-critical :marked - Do **not** specify singleton `providers` in shared modules. + Do **not** specify app-wide singleton `providers` in a shared module. + A lazy loaded module that imports that shared module will make its own copy of the service. a#core-module .l-main-section @@ -1003,7 +1013,7 @@ a#prevent-reimport ## Prevent reimport of the _CoreModule_ Only the root `AppModule` should import the `CoreModule`. - [Bad things happen](#q-why-it-is-bad) if a lazy loaded module imports it. + [Bad things happen](../cookbook/ngmodule-faq.html#q-why-it-is-bad) if a lazy loaded module imports it. We could _hope_ that no developer makes that mistake. Or we can guard against it and fail fast by adding the following `CoreModule` constructor. @@ -1032,1096 +1042,12 @@ a#prevent-reimport Now `parentModule` exists and the constructor throws the error. :marked ### Conclusion - We're done with the tutorial portion of the chapter. - You can examine and download the complete source for this final version from the live example. - - The next section summarizes the `NgModule` API. -.l-hr - -a#ngmodule-properties -.l-main-section -:marked - ## *NgModule* properties - - The following chart summarizes the `NgModule` metadata properties. -// - export interface NgModuleMetadataType { - providers?: any[]; - declarations?: Array; - imports?: Array; - exports?: Array; - entryComponents?: Array; - bootstrap?: Array; - schemas?: Array; - } - -table - tr - th Property - th Description - tr - td(style="vertical-align: top") declarations - td - :marked - A list of [declarable](#q-declarables) classes, - the **component**, **directive** and **pipe** classes that _belong to this module_. - - These declared classes are visible within the module but invisible to - components in a different module unless (a) they are _exported_ from this module and - (b) that other module _imports_ this one. - - Components, directives and pipes must belong to _exactly_ one module. - The compiler emits an error if we try to declare the same class in more than one module. - - **Do not re-declare a class imported from another module.** - - tr - td(style="vertical-align: top") providers - td - :marked - A list of dependency injection providers. - - Angular registers these providers with the root injector of the module's execution context. - That's the application's root injector for all modules loaded when the application starts. - - Angular can inject one of these provider services into any component in the application. - If this module provides the `HeroService`, or any module loaded at launch provides the `HeroService`, - Angular can inject the same `HeroService` intance into any app component. - - A lazy loaded module has its own sub-root injector which typically - is a direct child of the application root injector. - - Lazy loaded services are scoped to the lazy module's injector. - If a lazy loaded module also provides the `HeroService`, - any component created within that module's context (e.g., 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. - - tr - td(style="vertical-align: top") imports - td - :marked - A list of supporting modules. - - Specifically, the list of modules whose exported components, directives or pipes - are referenced by the component templates declared in this module. - - A component template can [reference](#q-template-reference) another component, directive or pipe - on two conditions: either the referenced class is declared in this module - or the class was imported from another module. - - A component can use the `NgIf` and `NgFor` directives only because its parent module - imported the Angular `CommonModule` (perhaps indirectly by importing `BrowserModule`). - - We can import many standard directives with the `CommonModule`. - But some familiar directives belong to other modules. - A component template can bind with `[(ngModel)]` only after importing the Angular `FormsModule`. - tr - td(style="vertical-align: top") exports - td - :marked - A list of declarations — **component**, **directive**, and **pipe** classes — that - an importing module can use. - - Exported declarations are the module's _public API_. - A component in another module can [reference](#q-template-reference) _this_ module's `HeroComponent` - if (a) it imports this module and (b) this module exports `HeroComponent`. - - Declarations are private by default. - If this module does _not_ export `HeroComponent`, no other module can see it. - - Importing a module does _not_ automatically re-export the imported module's exports. - Module 'B' can't use `ngIf` just because it imported module `A` which imported `CommonModule`. - Module 'B' must import `CommonModule` itself. - - A module can list another module among its `exports` in which case - all of that module's public components, directives, and pipes are exported. - - [Re-export](#q-re-export) makes module transitivity explicit. - If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', - Module 'B' components can use `ngIf` even though 'B' itself didn't import `CommonModule`. - - tr - td(style="vertical-align: top") bootstrap - td - :marked - A list of components that can be [bootstrapped](#bootstrap). - - Usually there is only one component in this list, the _root component_ of the application. - - Angular can launch with multiple bootstrap components, - each with its own location in the host web page. - - A bootstrap component is automatically an `entryComponent` - - tr - td(style="vertical-align: top") entryComponents - td - :marked - A list of components that are _not_ [referenced](#q-template-reference) in a reachable component template. - - Most developers will never set this property. Here's why. - - The [_Angular Compiler_](#q-angular-compiler) must know about every component actually used in the application. - The compiler can discover most components by walking the tree of references - from one component template to another. - - But there's always at least one component that is not referenced in any template: - the root component, `AppComponent`, that we bootstrap to launch the app. - That's why it's called an _entry component_. - - Routed components are also _entry components_ because they aren't referenced in a template either. - The router creates them and drops them into the DOM near a ``. - - While the bootstrapped and routed components are _entry components_, - we usally don't have to add them to a module's `entryComponents` list. - - Angular automatically adds components in the module's `bootstrap` list to the `entryComponents` list. - The `RouterModule` adds routed components to that list. - - That leaves only two sources of undiscoverable components. - 1. Components bootstrapped using one of the imperative techniques. - 1. Components dynamically loaded into the DOM by some means other than the router. - - Both are advanced techniques that few developers will ever employ. - If you are one of those few, you'll have to add these components to the - `entryComponents` list yourself, either programmatically or by hand. - -a#faq -.l-main-section -:marked - ## FAQ: Frequently Asked Questions - - Declarations - * [What classes should I add to _declarations_?](#q-what-to-declare) - * [What is a _declarable_?](#q-declarable) - * [What classes should I *not* add to _declarations_?](#q-what-not-to-declare) - * [Why list the same component in multiple _NgModule_ properties?](#q-why-multiple-mentions) - * [What does "_Can't bind to 'x' since it isn't a known property of 'y'_" mean?](#q-why-cant-bind-to) - - Imports - * [What should I import?](#q-what-to-import) - * [Should I import _BrowserModule_ or _CommonModule_?](#q-browser-vs-common-module) - * [What if I import the same module twice?](#q-reimport) - - Exports - * [What should I export?](#q-what-to-export) - * [What should I *not* export?](#q-what-not-to-export) - * [Can I re-export imported classes and modules?](#q-re-export) - * [What is the _forRoot_ method?](#q-for-root) - - Service Providers - * [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) - * [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) - * [Should I add providers to the root _AppModule_ or the root _AppComponent_?](#q-root-component-or-module) - * [Why is it bad if _SharedModule_ provides a service to a lazy loaded module?](#q-why-it-is-bad) - * [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) - - Entry Components - * [What is an _entry component_?](#q-entry-component-defined) - * [What is the difference between a _bootstrap_ component and an _entry component_?](#q-bootstrap_vs_entry_component) - * [When do I add components to _entryComponents_?](#q-when-entry-components) - * [Why does Angular need _entryComponents_?](#q-why-entry-components) - - General - * [What kinds of modules should I have and how should I use them?](#q-module-recommendations) - * [What's the difference between Angular and JavaScript Modules?](#q-ng-vs-js-modules) - * [What is a "template reference"?](#q-template-reference) - * [How does Angular find components, directives, and pipes in a template?](#q-template-reference) - * [What is the Angular Compiler?](#q-angular-compiler) - -.l-hr - -a#q-what-to-declare -.l-main-section -:marked - ### What classes should I add to _declarations_? - - Add [declarable](#q-declarable) classes — components, directives, and pipes — to a `declarations` list. - - These classes must be declared in _exactly one_ module of the application. - Declare them in _this_ module if they _belong_ to this module. - -.l-hr - -a#q-declarable -.l-main-section -:marked - ### What is a _declarable_? - _Declarables_ are the class types — components, directives, and pipes — - that you can add to a module's `declarations` list. - They're the _only_ classes that you can add to `declarations`. + You made it! You can examine and download the complete source for this final version from the live example. + -.l-hr + ### Frequently Asked Questions -a#q-what-not-to-declare -.l-main-section -:marked - ### What classes should I _not_ add to _declarations_? - - Only [declarable](#q-declarable) classes can be added to a module's `declarations` list. - - Do *not* declare - * a class that is already declared in another module, whether an app module, @angular module, or 3rd party module - - * an array of directives imported from another module. - For example, do not declare FORMS_DIRECTIVES from `@angular/forms`. - - * module classes - - * service classes - - * non-Angular classes and objects such as - strings, numbers, functions, entity models, configurations, business logic, and helper classes. - -.l-hr - -a#q-why-multiple-mentions -.l-main-section -:marked - ### Why list the same component in multiple _NgModule_ properties? - - We often see `AppComponent` listed in both `declarations` and `bootstrap`. - We might see `HeroComponent` listed in `declarations`, `exports`, and `entryComponents`. - - That _feels_ redundant but these properties have different functions - and we can't infer that membership in one list implies membership in another list. - - * `AppComponent` could be declared in this module but not bootstrapped. - * `AppComponent` could be bootstrapped in this module but declared in a different feature module. - * `HeroComponent` could be imported from another app module (so we can't declare it) and re-exported by this module. - * `HeroComponent` could be exported for inclusion in an external component's template and also dynamically loaded in a pop-up dialog. - -.l-hr - -a#q-why-cant-bind-to -.l-main-section -:marked - ### What does "_Can't bind to 'x' since it isn't a known property of 'y'_" mean? - - This error usually means either that you neglected to declare the directive "x" - or you haven't imported the module to which "x" belongs. - - For example, if "x" is `ngModel`, you probably haven't imported the `FormsModule` from `@angular/forms`. - - Perhaps you declared "x" in an application sub-module but forgot to export it? - The "x" class won't be visible to other modules until you add it to the `exports` list. - -.l-hr - -a#q-what-to-import -.l-main-section -:marked - ### What should I import? - - Import modules whose public (exported) [declarable classes](#q-declarable) - you need to reference in this module's component templates. - - This invariably means importing `CommonModule` from `@angular/common` for access to - the Angular directives such as `NgIf` and `NgFor`. - You can import it directly or from another module that [re-exports](#q-reexport) it. - - Import `FormsModule` from `@angular/forms` - if your components have `[(ngModel)]` two-way binding expressions. - - Import _shared_ and _feature_ modules when this module's components incorporate their - components, directives, and pipes. - - Only [import _BrowserModule_](#q-browser-vs-common-module) in the root `AppModule`. - -.l-hr - -a#q-browser-vs-common-module -.l-main-section -:marked - ### Should I import _BrowserModule_ or _CommonModule_? - - The **root application module** (`AppModule`) of almost every browser application - should import `BrowserModule` from `@angular/core`. - - `BrowserModule` provides services that are essential to launch and run a browser app. - - `BrowserModule` also re-exports `CommonModule` from `@angular/common` - which means that component in the `AppModule` module also have access to - the Angular directives every app needs such as `NgIf` and `NgFor`. - - _Do not import_ `BrowserModule` in any other module. - *Feature modules* and *lazy loaded modules* should import `CommonModule` instead. - They need the common directives. They don't need to re-install the app-wide providers. -.l-sub-section - :marked - `BrowserModule` throws an error if you try to lazy load a module that imports it. -:marked - Importing `CommonModule` also frees feature modules for use on _any_ target platform, not just browsers, - a fact of some interest to authors of cross-platform libraries. - -.l-hr -a#q-reimport -.l-main-section -:marked - ### What if I import the same module twice? - - That's not a problem. When three modules all import Module 'A', - Angular evaluates Module 'A' once, the first time it encounters it, and does not do so again. - - That's true at whatever level `A` appears in a hierarchy of imported modules. - When Module 'B' imports Module 'A', Module 'C' imports 'B', and Module 'D' imports `[C, B, A]`, - then 'D' triggers the evaluation of 'C' which triggers the evaluation of 'B' which evaluates 'A'. - When Angular gets to the 'B' and 'A' in 'D', they're already cached and ready to go. - - Angular does not like modules with circular references so don't let Module 'A' import Module 'B' which imports Module 'A'. - -.l-hr -a#q-what-to-export -.l-main-section -:marked - ### What should I export? - - Export [declarable](#q-declarable) classes that components in _other_ modules - should be able to reference in their templates. These are your _public_ classes. - If you don't export a class, it stays _private_, visible only to other component - declared in this module. - - You _can_ export any declarable class — components, directives, and pipes — - whether it is declared in this module or in an imported module. - - You _can_ re-export entire imported modules which effectively re-exports all of their exported classes. - A module can even export a module that it doesn't import. - -.l-hr - -a#q-what-not-to-export -.l-main-section -:marked - ### What should I *not* export? - - Do *not* export - - * Private components, directives, and pipes that you need only within components declared in this module. - If you don't want another module to see it, don't export it. - - * Non-declarable objects such as services, functions, configurations, entity models, etc. - - * Components that are only loaded dynamically by the router or by bootstrapping. - Such [entry components](#q-entry-component-defined) can never be selected in another component's template. - There's no harm in exporting them but no benefit either. - - * Pure service modules that don't have public (exported) declarations. - For example, there is no point in re-exporting `HttpModule` because it doesn't export anything. - It's only purpose is to add http service providers to the application as a whole. - -.l-hr - -a#q-reexport -a#q-re-export -.l-main-section -:marked - ### Can I re-export classes and modules? - - Absolutely! - - Modules are a great way to selectively aggregate classes from other modules and - re-export them in a consolidated, convenience module. - - A module can re-export entire modules which effectively re-exports all of their exported classes. - Angular's own `BrowserModule` exports a couple of modules like this: -code-example. - exports: [CommonModule, ApplicationModule] - -:marked - A module can export a combination of its own declarations, selected imported classes, and imported modules. -.l-sub-section - :marked - Don't bother re-exporting pure service modules. - Pure service modules don't export [declarable](#q-declarable) classes that another module could use. - For example, there is no point in re-exporting `HttpModule` because it doesn't export anything. - It's only purpose is to add http service providers to the application as a whole. - -.l-hr - -a#q-for-root -.l-main-section -:marked - ### What is the _forRoot_ method? - - The `forRoot` static method is a convention that makes it easy for developers to configure the module's provider(s). - - The `RouterModule.forRoot` method is a good example. - Apps pass a `Routes` object to `RouterModule.forRoot` in order to configure the app-wide `Router` service with routes. - `RouterModule.forRoot` returns a [ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html). - We add that result to the `imports` list of the root `AppModule`. - -.alert.is-important - :marked - Only call and import a `.forRoot` result in the root application module, `AppModule`. - Importing it in any other module, particularly in a lazy loaded module, - is contrary to the intent and is likely to produce a runtime error. -:marked - `RouterModule` also offers a `forChild` static method for configuring the routes of lazy loaded modules. - - **_forRoot_** and **_forChild_** are conventional names for methods that - configure services in root and feature modules respectively. - - Angular doesn't recognize these names but Angular developers do. - Follow this convention when you write similar modules with configurable service providers. - -.l-hr - -a#q-module-provider-visibility -.l-main-section -:marked - ### Why is a service provided in a feature module visible everywhere? - - Providers listed in the `@NgModule.providers` of a bootstrapped module have **application scope**. - Adding a service provider to `@NgModule.providers` effectively publishes the service to the entire application. - - When we import a module, - Angular adds the module's service providers (the contents of its `providers` list) - to the application _root injector_. - - This makes the provider visible to every class in the application that knows the provider's lookup token. - - This is by design. - Extensibility through module imports is a primary goal of the Angular module system. - Merging module providers into the application injector - makes it easy for a module library to enrich the entire application with new services. - By adding the `HttpModule` once, every application component can make http requests. - - However, this can feel like an unwelcome surprise if you are expecting the module's services - to be visible only to the components declared by that feature module. - If the `HeroModule` provides the `HeroService` and the root `AppModule` imports `HeroModule`, - any class that knows the `HeroService` _type_ can inject that service, - not just the classes declared in the `HeroModule`. - -.l-hr - -a#q-lazy-loaded-module-provider-visibility -.l-main-section -:marked - ### Why is a service provided in a lazy loaded module visible only to that module? - - Unlike providers of the modules loaded at launch, - providers of lazy loaded modules are *module-scoped*. - - When the Angular router lazy-loads a module, it creates a new execution context. - That [context has its own injector](#q-why-child-injector "Why Angular creates a child injector") which is a direct child of the application injector. - - The router adds the lazy module's providers and the providers of its imported modules to this child injector. - - These providers are insulated from changes to application providers with the same lookup token. - 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. - -.l-hr -a#q-module-provider-duplicates -.l-main-section -:marked - ### What if two modules provide the _same_ service? - - When two imported modules, loaded at the same time, list a provider with the same token, - the second module's provider "wins". That's because both providers are added to the same injector. - - When Angular looks to inject a service for that token, - it creates and delivers the instance created by the second provider. - - _Every_ class that injects this service gets the instance created by the second provider. - Even classes declared within the first module get the instance created by the second provider. - _This can be an unwelcome surprise_. - - If Module A provides a service for token 'X' and imports a module B - that also provides a service for token 'X', then Module A's service definition "wins". - - The service provided by the root `AppModule` takes precedence over services provided by imported modules. - The `AppModule` always wins. - -.l-hr - -a#q-component-scoped-providers -.l-main-section -:marked - ### How do I restrict service scope to a module? - - When a module is loaded at application launch, - its `@NgModule.providers` have ***application-wide scope***. - They are visible throughout the application as discussed [above](#application-scoped-providers). - - Imported providers are easily replaced by providers from another imported module. - Such replacement may be by design. It could be unintentional and have adverse consequences. - -.alert.is-important - :marked - As a general rule, import modules with providers _exactly once_, preferably in the application's _root module_. - That's also usually the best place to configure, wrap, and override them. - -:marked - Suppose a module requires a customized `HttpBackend` that adds a special header for all Http requests. - If another module elsewhere in the application also customizes `HttpBackend` - or merely imports the `HttpModule`, it could override this module's `HttpBackend` provider, - losing the special header. The server will reject http requests from this module. - -.alert.is-important - :marked - Avoid this problem by importing the `HttpModule` only in the `AppModule`, the application _root module_. - -:marked - If you must guard against this kind of "provider corruption", *don't rely on a launch-time module's `providers`.* - - Load the module lazily if you can. - Angular gives a [lazy-loaded module](#q-lazy-loaded-module-provider-visibility) its own child injector. - The module's providers are visible only within the component tree created with this injector. - - If you must load the module eagerly, when the application starts, - ***provide the service in a component instead.*** - - Continuing with the same example, suppose the components of a module truly require a private, custom `HttpBackend`. - - Create a "top component" that acts as the root for all of the module's components. - Add the custom `HttpBackend` provider to the top component's `providers` list rather than the module's `providers`. - Recall that Angular creates a child injector for each component instance and populates the injector - with the component's own providers. - - When a child of this component _asks_ for the `HttpBackend` service, - Angular provides the local `HttpBackend` service, - not the version provided in the application root injector. - Child components will make proper http requests no matter what other modules do to `HttpBackend`. - - Be sure to create module components as children of this module's top component. - - You can embed the child components in the top component's template. - Alternatively, make the top component a routing host by giving it a ``. - Define child routes and let the router load module components into that outlet. - -.l-hr - -a#q-root-component-or-module -.l-main-section -:marked - ### Should I add providers to the root _AppModule_ or the root _AppComponent_? - - Most apps launch with an initial set of service providers. - Should we register those providers on the root `AppModule` (`@NgModule.providers`) or - the root `AppComponent` (`@Component.providers`)? - - **_List such providers in the root_ `AppModule` _unless you have a compelling reason to do otherwise_**. - - Angular registers all startup module providers with the application root injector. - The services created from root injector providers are available to the entire application. - They are _application-scoped_. - - 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. - `AppComponent`services are available to that component and its component tree. - They are _component-scoped_. - - The `AppComponent`'s injector is a _child_ of the root injector, one down in the injector hierarchy. - That is _almost_ the entire application for apps that don't use the router. - But "almost" isn't good enough for routed applications. - - `AppComponent` services don't exist at the root level where routing operates. - Lazy loaded modules can't reach them. - In this sample applications, if we had registered `UserService` in the `AppComponent`, - the `HeroComponent` couldn't inject it. - 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. - We _should_ register a service in `AppComponent` providers if the service must be hidden - from components outside the `AppComponent` tree. - - These are special cases. - When in doubt, register with the `AppModule`. - -.l-hr - -a#q-why-it-is-bad -.l-main-section -:marked - ### Why is it bad if _SharedModule_ provides a service to a lazy loaded module? - - This question arose earlier when we discussed the importance - of keeping providers out of the [_SharedModule_](#no-shared-module-providers). - - Suppose we had listed the `UserService` in the module's `providers` (which we did not). - Suppose every module imports this `SharedModule` (which they all do). - - When the app starts, Angular eagerly loads the `AppModule` and the `ContactModule`. - - Both instances of the imported `SharedModule` would provide the `UserService`. - Angular registers one of them in the root app injector (see [above](#q-reimport)). - Then some component injects `UserService`, Angular finds it in the app root injector, - and delivers the app-wide singleton `UserService`. No problem. - - Now consider the `HeroModule` _which is lazy loaded!_ - - When the router lazy loads the `HeroModule`, it creates a child injector and registers the `UserService` - provider with that child injector. The child injector is _not_ the root injector. - - When Angular creates a lazy `HeroComponent`, it must inject a `UserService`. - This time it finds a `UserService` provider in the lazy module's _child injector_ - and creates a _new_ instance of the `UserService`. - This is an entirely different `UserService` instance - than the app-wide singleton version that Angular injected in one of the eagerly loaded components. - - That's almost certainly a mistake. -.l-sub-section - :marked - Prove it for yourself. - Run the live example. - Modify the `SharedModule` so that it provides the `UserService` rather than the `CoreModule`. - Then toggle between the "Contact" and "Heroes" links a few times. - The username goes bonkers as the Angular creates a new `UserService` instance each time. - -.l-hr - -a#q-why-child-injector -.l-main-section -:marked - ### Why does lazy loading create a child injector? - - Angular adds `@NgModule.providers` to the application root injector ... unless the module is lazy loaded. - Then it creates a _child injector_ and adds the module's providers to the child injector. - - This means that a module behaves differently depending on whether it is loaded during application start - or lazy loaded later. Neglecting that difference can lead to [adverse consequences](#q-why-it-is-bad). - - Why doesn't Angular add lazy loaded providers to the app root injector as it does for eagerly loaded modules? - Why the inconsistency? - - The answer is grounded in a fundamental characteristic of the Angular dependency injection system. - An injector can add providers _until it is first used_. - Once an injector starts creating and delivering services, its provider list is frozen. No new providers allowed. - - When an applications starts, Angular first configures the root injector with the providers of all eagerly loaded modules - _before_ creating its first component and injecting any of the provided services. - Once the application begins, the app root injector is closed to new providers. - - Time passes. Application logic triggers lazy loading of a module. - Angular must add the lazy loaded module's providers to an injector _somewhere_. - It can't added them to the app root injector because that injector is closed to new providers. - So Angular creates a new child injector for the lazy loaded module context. - -.l-hr - -a#q-is-it-loaded -.l-main-section -:marked - ### How can I tell if a module or service was previously loaded? - - Some modules and its services should only be loaded once by the root `AppModule`. - Importing the module a second time by lazy loading a module could [produce errant behavior](#q-why-it-is-bad) - that may be difficult to detect and diagnose. - - We can guard against that danger by writing a constructor that attempts to inject the module or service - from the root app injector. If the injection succeeds, the class has been loaded a second time. - We can throw an error or take other remedial action. - - Certain Angular modules (such as `BrowserModule`) implements such a guard - as does this sample's [_CoreModule_ constructor](#prevent-reimport). - -.l-hr - -a#q-entry-component-defined -.l-main-section -:marked - ### What is an _entry component_? - - Any component that Angular loads _imperatively_ by type is an _entry component_, - - A component loaded _declaratively_ via its selector is _not_ an entry component. - - Most application components are loaded declaratively. - Angular uses the component's selector to locate the element in the template. - It then creates the HTML representation of the component and inserts it into the DOM at the selected element. - These are not entry components. - - A few components are only loaded dynamically and are _never_ referenced in a component template. - - The bootstrapped root `AppComponent` is an _entry component_. - True, its selector matches an element tag in `index.html`. - But `index.html` is not a component template and the `AppComponent` - selector doesn't match an element in any component template. - - Angular loads `AppComponent` dynamically either because we listed it _by type_ in `@NgModule.bootstrap` - or because we boostrapped it imperatively with the module's `ngDoBootstrap` method. - - Components in route definitions are also _entry components_. - A route definition refers to a component by its _type_. - The router ignores a routed component's selector (if it even has one) and - loads the component dynamically into a `RouterOutlet`. - - The compiler can't discover these _entry components_ by looking for them in other component templates. - We must tell it about them ... by adding them to the `entryComponents` list. - - Angular automatically adds two kinds of components to the module's `entryComponents`: - 1. the component in the `@NgModule.bootstrap` list - 1. components referenced in router configuration - - We don't have to mention these components explicitly although it does not harm to do so. - -.l-hr - -a#q-bootstrap_vs_entry_component -.l-main-section -:marked - ### What's the difference between a _bootstrap_ component and an _entry component_? - - A bootstrapped component _is_ an [entry component](#entry-component-defined). - It's an entry component that Angular loads into the DOM during the bootstrap (application launch) process. - Other entry components are loaded dynamically by other means such as with the router. - - The `@NgModule.bootstrap` property tells the compiler _both_ that this is an entry component _and_ - that it should generate code to bootstrap the application with this component. - - There is no need to list a component in both the `bootstrap` and `entryComponent` lists - although it is harmless to do so. - -.l-hr - -a#q-when-entry-components -.l-main-section -:marked - ### When do I add components to _entryComponents_? - - Most application developers won't need to add components to the `entryComponents`. - - Angular adds certain components to _entry components_ automatically. - Components listed in `@NgModule.bootstrap` are added automatically. - Components referenced in router configuration are added automatically. - These two mechanisms account for almost all entry components. - - If your app happens to bootstrap or dynamically load a component _by type_ in some other manner, - you'll have to add it to `entryComponents` explicitly. - - Although it's harmless to add components to this list, - it's best to add only the components that are truly _entry components_. - Don't include components that [are referenced](#q-template-reference) - in the templates of other components. - -.l-hr - -a#q-why-entry-components -.l-main-section -:marked - ### Why does Angular need _entryComponents_? - _Entry components_ are also declared. - Why doesn't the Angular compiler generate code for every component in `@NgModule.declarations`? - Then we wouldn't need entry components. - - The reason is _tree shaking_. For production apps we want to load the smallest, fastest code possible. - The code should contain only the classes that we actually need. - It should exclude a component that's never used, whether or not that component is declared. - - In fact, many libraries declare and export components we'll never use. - The _tree shaker_ will drop these components from the final code package - if we don't reference them. - - If the [Angular compiler](#angular-compilar) generated code for every declared component, - it would defeat the purpose of the tree shaker. - - Instead, the compiler adopts a recursive strategy that generates code only for the components we use. - - It starts with the entry components, - then it generates code for the declared components it [finds](#q-template-reference) in an entry component's template, - then for the declared components it discovers in the templates of previously compiled components, - and so on. At the end of the process, it has generated code for every entry component - and every component reachable from an entry component. - - If a component isn't an _entry component_ or wasn't found in a template, - the compiler omits it. - - -.l-hr - -a#q-module-recommendations -.l-main-section -:marked - #### What kinds of modules should I have and how should I use them? - - Every app is different and developers have varying levels of experience and comfort with the available choices. - Some suggestions and guidelines appear to have wide appeal. - -.alert.is-important - :marked - The following is preliminary guidance based on early experience using Angular modules in a few applications. - Read with appropriate caution and reflection. - -:marked - #### _SharedModule_ - Create a `SharedModule` with the components, directives, and pipes that you use - everywhere in your app. This module should consist entirely of `declarations` - most of them exported. - - It may re-export other [widget modules](#widget-feature-module) such as `CommonModule`, - `FormsModule` and modules with the UI controls that you use most widely. - - It should ***not*** have `providers` for reasons [explained earlier](#q-why-it-is-bad). - Nor should any of its imported or re-exported modules have `providers`. - Know what you're doing and why if you deviate from this guideline. - - Import the `SharedModule` in your _feature_ modules, - both those loaded when the app starts and those you lazy load later. - - #### _CoreModule_ - Create a `CoreModule` with `providers` for the singleton services you load when the application starts. - - Import `CoreModule` in the root `AppModule` only. - Never import `CoreModule` in any module other than the root `AppModule`. - - Consider making `CoreModule` a [pure services module](#service-feature-module) with no `declarations`. - -.l-sub-section - :marked - This chapter sample departs from that advice by declaring and exporting two components that are - only used within the root `AppComponent` declared by `AppModule`. - Someone following this guideline strictly would have declared these components in the `AppModule` instead. - -:marked - #### Feature Modules - Create _Feature Modules_ around specific application business domains, user workflows, and utility collections. - - Feature modules tend to fall into one of these four groups: - * [Domain Feature Modules](#domain-feature-module) - * [Routed Feature Modules](#routed-feature-module) - * [Service Feature Modules](#service-feature-module) - * [Widget Feature Modules](#widget-feature-module) - -.l-sub-section - :marked - Real world modules are often hybrids that knowingly deviate from the following guidelines. - They are guidelines, not laws. - Follow them until you have a good reason to do otherwise. - -table - tr - th(style="vertical-align: top") Feature Module - th(style="vertical-align: top") Guidelines - tr - td(style="vertical-align: top")Domain - td - :marked - Domain Feature Modules deliver a user experience **dedicated to a particular application domain** - like editing a customer or placing an order. - - They typically have a top component that acts as the feature root. - Private, supporting sub-components descend from it. - - Domain feature module consist mostly of _declarations_. - Only the top component is exported. - - Domain feature modules rarely have _providers_. - When they do, the lifetime of the provided services - should be the same as the lifetime of the module. - - Do not provide application-wide singleton services in a domain feature module. - - Domain feature modules are typically imported _exactly once_ by a larger feature module. - - They might be imported by the root `AppModule` of a small application that lacks routing. - - .l-sub-section - :marked - For an example, see this chapter's first version of the [_ContactModule_](#contact-module-v1) - before we introduced routing. - tr - td(style="vertical-align: top")Routed - td - :marked - _Routed Feature Modules_ are _Domain Feature modules_ - whose top components are the **targets of router navigation routes**. - - All lazy loaded modules are routed feature modules by nature. - - This chapter's `ContactModule`, `HeroModule` and `CrisisModule` are routed feature modules. - - Routed Feature Modules _should not export anything_. - They don't have to because none of their components ever appear in the template of an external component. - - Routed Feature Modules are _never imported_. - - Routed Feature Modules rarely have _providers_ for reasons [explained earlier](#q-why-it-is-bad). - When they do, the lifetime of the provided services - should be the same as the lifetime of the module. - - Do not provide application-wide singleton services in a routed feature module - or in a module that the routed module imports. - - tr - td(style="vertical-align: top")Service - td - :marked - _Service Modules_ **provide utility services** such as data access and messaging. - - Ideally they consist entirely of _providers_ and have no _declarations_. - The `CoreModule` and Angular's `HttpModule` are good examples. - - Service Modules should _only_ be imported by the root `AppModule`. - - Do **not** import them in other feature modules. - Know what you're doing and why if you deviate from this guideline. - tr - td(style="vertical-align: top")Widget - td - :marked - A _Widget Module_ makes **components, directives, and pipes** available to external modules. - - `CommonModule` and `SharedModule` are widget modules. - Many third party UI component libraries are widget modules. - - A Widget Module should consist entirely of _declarations_, most of them exported. - - A Widget Module should rarely have _providers_. - Know what you're doing and why if you deviate from this guideline. - - Import Widget Modules in any module whose component templates need the widgets. - -:marked - The following table summarizes the key characteristics of each _Feature Module_ group. -.l-sub-section - :marked - Real world modules are often hybrids that knowingly deviate from these guidelines. -table - tr - th Feature Module - th Declarations - th Providers - th Exports - th Imported By - th Examples - tr - td Domain - td Yes - td Rare - td Top Component - td Feature, AppModule - td ContactModule (before routing) - tr - td Routed - td Yes - td Rare - td None - td Nobody - td ContactModule, HeroModule, CrisisModule - tr - td Service - td No - td Yes - td No - td AppModule - td HttpModule, CoreModule - tr - td Widget - td Yes - td Rare - td Yes - td Feature - td CommonModule, SharedModule - -.l-hr - -a#q-ng-vs-js-modules -.l-main-section -:marked - ### What's the difference between Angular and JavaScript Modules? - - Angular and JavaScript are two different yet complementary module systems. - - In modern JavaScript, [every file is a _module_](http://exploringjs.com/es6/ch_modules.html). - Within each file we write an `export` statement to make parts of the module public: - -code-example(format='.'). - export class AppComponent { ... } - -:marked - Then we `import` a part in another module: - -code-example(format='.'). - import { AppComponent } from './app.component'; - -:marked - This kind of modularity is a feature of the _JavaScript language_. - - An _Angular Module_ is a feature of _Angular_ itself. - - Angular's `NgModule` also has `imports` and `exports` and they serve a similar purpose. - - We _import_ other Angular modules so we can use their exported classes in component templates. - We _export_ this Angular module's classes so they can be imported and used by components of _other_ modules. - - The Angular module classes differ from JavaScript module class in three key respects: - - 1. An Angular module bounds [_declarable classes_](#q-declarables) only. - Declarables are the only classes that matter to the [Angular compiler](#angular-compiler). - - 1. Instead of defining all member classes in one giant file (as in a JavaScript module), - we list the module's classes in the `@NgModule.declarations` list. - - 1. An Angular module can only export the [_declarable classes_](#q-declarables) - it owns or imports from other modules. - It doesn't declare or export any other kind of class. - - The Angular Module is also special in another way. - Unlike JavaScript modules, an Angular module can extend the _entire_ application with services - by adding providers to the `@NgModule.providers` list. - -.alert.is-important - :marked - The provided services do not belong to the module nor are they scoped to the declared classes. - They are available _everywhere_. - -:marked - Here's an _Angular Module_ class with imports, exports, and declarations. -+makeExample('ngmodule/ts/app/contact/contact.module.2.ts', 'class')(format=".") -:marked - Of course we use _JavaScript_ modules to write _Angular_ modules as seen in the complete `contact.module.ts` file: -+makeExample('ngmodule/ts/app/contact/contact.module.2.ts', '', 'app/contact/contact.module.ts')(format=".") - -.l-hr - -a#q-template-reference -.l-main-section -h4. - How does Angular find components, directives, and pipes in a template?
What is a template reference? -:marked - The [Angular compiler](#q-angular-compiler) looks inside component templates - for other components, directives, and pipes. When it finds one, that's a "template reference". - - The Angular compiler finds a component or directive in a template when it can match the **selector** of that - component or directive to some HTML in that template. - - The compiler finds a pipe if the pipe's **name** appears within the pipe syntax of the template HTML. - - Angular only matches selectors and pipe names for classes that are declared by this module - or exported by a module that this module imports. - -.l-hr - -a#q-angular-compiler -.l-main-section -:marked - ### What is the Angular Compiler? - - The _Angular Compiler_ converts the application code we write into highly performant JavaScript code. - The `@NgModule` metadata play an important role in guiding the compilation process. - - The code we write is not immediately executable. - Consider **components**. - Components have templates that contain custom elements, attribute directives, Angular binding declarations, - and some peculiar syntax that clearly isn't native HTML. - - The _Angular Compiler_ reads the template markup, - combines it with the corresponding component class code, and emits _component factories_. - - A component factory creates a pure, 100% JavaScript representation - of the component that incorporates everything described in its `@Component` metadata: - the HTML, the binding instructions, the attached styles ... everything. - - Because **directives** and **pipes** appear in component templates, - the _Angular Compiler_ incorporates them into compiled component code too. - - `@NgModule` metadata tells the _Angular Compiler_ what components to compile for this module and - how to link this module with other modules. + Now that you understand Angular Modules, you may be interested + in the companion [Angular Module FAQs](../cookbook/ngmodule-faq.html "Angular Module FAQs") cookbook + with its ready answers to specific design and implementation questions.