diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index 6bd29d2f97..63382b3243 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -16,11 +16,6 @@ "intro": "Learn how AngularJS concepts and techniques map to Angular." }, - "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" @@ -56,6 +51,11 @@ "intro": "Translate the app's template text into multiple languages." }, + "ngmodule-faq": { + "title": "NgModule FAQs", + "intro": "Answers to frequently asked questions about @NgModule." + }, + "set-document-title": { "title": "Set the Document Title", "intro": "Setting the document or window title using the Title service." diff --git a/public/docs/ts/latest/cookbook/ngmodule-faq.jade b/public/docs/ts/latest/cookbook/ngmodule-faq.jade index d53f55f1be..c2f43a68ca 100644 --- a/public/docs/ts/latest/cookbook/ngmodule-faq.jade +++ b/public/docs/ts/latest/cookbook/ngmodule-faq.jade @@ -2,23 +2,23 @@ block includes include ../_util-fns :marked - **Angular Modules** help organize an application into cohesive blocks of functionality. + NgModules 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. + The [NgModules](../guide/ngmodule.html) page guides you + 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. + This page answers the questions many developers ask about NgModule design and implementation. .alert.is-important :marked - These FAQs assume that you have already read the [Angular Module](../guide/ngmodule.html) chapter. + These FAQs assume that you have read the [NgModules](../guide/ngmodule.html) page. :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) + * [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) + * [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) @@ -33,12 +33,12 @@ block includes 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) + * [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 app-wide providers to the root _AppModule_ or the root _AppComponent_?](#q-root-component-or-module) * [Should I add other providers to a module or a component?](#q-component-or-module) - * [Why is it bad if _SharedModule_ provides a service to a lazy loaded module?](#q-why-bad) + * [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) @@ -51,21 +51,21 @@ block includes 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) + * [What is a "template reference"?](#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_? + ## What classes should I add to _declarations_? - Add [declarable](#q-declarable) classes — components, directives, and pipes — to a `declarations` list. + 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 these classes in _exactly one_ module of the application. Declare them in _this_ module if they _belong_ to this module. .l-hr @@ -73,10 +73,10 @@ a#q-what-to-declare a#q-declarable .l-main-section :marked - ### What is a _declarable_? + ## What is a _declarable_? - _Declarables_ are the class types — components, directives, and pipes — - that you can add to a module's `declarations` list. + 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 @@ -84,21 +84,17 @@ a#q-declarable a#q-what-not-to-declare .l-main-section :marked - ### What classes should I _not_ add to _declarations_? + ## What classes should I _not_ add to _declarations_? - Only [declarable](#q-declarable) classes can be added to a module's `declarations` list. + Add only [declarable](#q-declarable) classes 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 + Do *not* declare the following: + * A class that's already declared in another module, whether an app module, @NgModule, or third-party module. + * An array of directives imported from another module. + For example, don't 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 @@ -106,45 +102,46 @@ a#q-what-not-to-declare a#q-why-multiple-mentions .l-main-section :marked - ### Why list the same component in multiple _NgModule_ properties? + ## 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`. + `AppComponent` is often listed in both `declarations` and `bootstrap`. + You 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. + While that seems redundant, these properties have different functions. + Membership in one list doesn't imply 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. + * `HeroComponent` could be imported from another app module (so you can't declare it) and re-exported by this module. + * `HeroComponent` could be exported for inclusion in an external component's template + as well as 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? + ## 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. + This error usually means that you haven't declared the directive "x" + or 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. + The "x" class isn't 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? + ## 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 + This always 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. @@ -154,65 +151,64 @@ a#q-what-to-import 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`. + Import only [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_? + ## Should I import _BrowserModule_ or _CommonModule_? - The **root application module** (`AppModule`) of almost every browser application + The *root application module* (`AppModule`) of almost every browser application should import `BrowserModule` from `@angular/platform-browser`. `BrowserModule` provides services that are essential to launch and run a browser app. - `BrowserModule` also re-exports `CommonModule` from `@angular/common` + `BrowserModule` also re-exports `CommonModule` from `@angular/common`, which means that components in the `AppModule` module also have access to - the Angular directives every app needs such as `NgIf` and `NgFor`. + 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. + *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. + Importing `CommonModule` also frees feature modules for use on _any_ target platform, not just browsers. .l-hr a#q-reimport .l-main-section :marked - ### What if I import the same module twice? + ## 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. + Angular evaluates Module 'A' once, the first time it encounters it, and doesn't 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'. + 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'. + Angular doesn't 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? + ## 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. + are 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_ export any declarable class—components, directives, and pipes—whether + it's 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. + 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 @@ -220,21 +216,18 @@ a#q-what-to-export a#q-what-not-to-export .l-main-section :marked - ### What should I *not* export? + ## What should I *not* export? - Do *not* export + Don't export the following: * 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. - + * Non-declarable objects such as services, functions, configurations, and entity models. * 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. - + While there's no harm in exporting them, there's also no benefit. * 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. + For example, there's 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 @@ -243,14 +236,14 @@ a#q-reexport a#q-re-export .l-main-section :marked - ### Can I re-export classes and modules? + ## Can I re-export classes and modules? - Absolutely! + 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. + 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] @@ -261,7 +254,7 @@ code-example. :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. + For example, there's 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 @@ -269,24 +262,24 @@ code-example. a#q-for-root .l-main-section :marked - ### What is the _forRoot_ method? + ## 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 `forRoot` static method is a convention that makes it easy for developers to configure the module's providers. 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`. + You 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. + Importing it in any other module, particularly in a lazy-loaded module, + is contrary to the intent and will likely produce a runtime error. :marked - `RouterModule` also offers a `forChild` static method for configuring the routes of lazy loaded modules. + `RouterModule` also offers a `forChild` static method for configuring the routes of lazy-loaded modules. - **_forRoot_** and **_forChild_** are conventional names for methods that + _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. @@ -297,24 +290,24 @@ a#q-for-root a#q-module-provider-visibility .l-main-section :marked - ### Why is a service provided in a feature module visible everywhere? + ## Why is a service provided in a feature module visible everywhere? - Providers listed in the `@NgModule.providers` of a bootstrapped module have **application scope**. + 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, + When you 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. + Extensibility through module imports is a primary goal of the NgModule 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 + However, this might feel like an unwelcome surprise if you expect 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, @@ -325,25 +318,26 @@ a#q-module-provider-visibility 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? + ## 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*. + 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. + 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, + 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? + ## 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. @@ -353,7 +347,6 @@ a#q-module-provider-duplicates _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". @@ -366,14 +359,14 @@ a#q-module-provider-duplicates a#q-component-scoped-providers .l-main-section :marked - ### How do I restrict service scope to a module? + ## 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. + its `@NgModule.providers` have *application-wide scope*; + that is, 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. + Such replacement might be by design. It could be unintentional and have adverse consequences. .alert.is-important :marked @@ -385,12 +378,9 @@ a#q-component-scoped-providers 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. + + To avoid this problem, import the `HttpModule` only in the `AppModule`, the application _root 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. @@ -398,7 +388,7 @@ a#q-component-scoped-providers 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.*** + *provide the service in a component instead.* Continuing with the same example, suppose the components of a module truly require a private, custom `HttpBackend`. @@ -407,10 +397,10 @@ a#q-component-scoped-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, + 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`. + Child components 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. @@ -423,38 +413,36 @@ a#q-component-scoped-providers a#q-root-component-or-module .l-main-section :marked - ### Should I add app-wide providers to the root _AppModule_ or the root _AppComponent_? + ## Should I add application-wide providers to the root _AppModule_ or the root _AppComponent_? -.alert.is-helpful - :marked - Register application-wide providers in the root `AppModule`, not in the `AppComponent`. -:marked + Register application-wide providers in the root `AppModule`, not in the `AppComponent`. + Lazy-loaded modules and their components can inject `AppModule` services; - they cannot inject `AppComponent` services. + they can't inject `AppComponent` services. Register a service in `AppComponent` providers _only_ if the service must be hidden - from components outside the `AppComponent` tree. This is a rare exceptional use case. + from components outside the `AppComponent` tree. This is a rare use case. More generally, [prefer registering providers in modules](#q-component-or-module) to registering in components. - #### **_Discussion_:** + ### Discussion 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. + Certain services (such as 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 only to that component and its component tree. + `AppComponent` services are available only 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. + For applications that don't use the router, that's _almost_ the entire application. + But for routed applications, "almost" isn't good enough. `AppComponent` services don't exist at the root level where routing operates. - Lazy loaded modules can't reach them. - In the Angular Module Chapter sample applications, if we had registered `UserService` in the `AppComponent`, + Lazy-loaded modules can't reach them. + In the NgModule page sample applications, if you had registered `UserService` in the `AppComponent`, the `HeroComponent` couldn't inject it. The application would fail the moment a user navigated to "Heroes". @@ -463,7 +451,7 @@ a#q-root-component-or-module a#q-component-or-module .l-main-section :marked - ### Should I add other providers to a module or a component? + ## Should I add other providers to a module or a component? In general, prefer registering feature-specific providers in modules (`@NgModule.providers`) to registering in components (`@Component.providers`). @@ -475,31 +463,32 @@ a#q-component-or-module For example, a hero editing component that needs a private copy of a caching hero service should register the `HeroService` with the `HeroEditorComponent`. Then each new instance of the `HeroEditorComponent` gets its own cached service instance. - The changes that editor makes to heroes in its service do not touch the hero instances elsewhere in the application. + The changes that editor makes to heroes in its service don't touch the hero instances elsewhere in the application. - [Always register _application-wide_ services with the root `AppModule`](q-root-component-or-module), + [Always register _application-wide_ services with the root `AppModule`](#q-root-component-or-module), not the root `AppComponent`. .l-hr a#q-why-bad .l-main-section :marked - ### Why is it bad if _SharedModule_ provides a service to a lazy loaded module? + ## 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`. + This question is addressed in the [Why UserService isn't shared](../guide/ngmodule.html#no-shared-module-providers) + section of the [NgModules](../guide/ngmodule.html) page, + which discusses 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 the `UserService` was listed in the module's `providers` (which it isn't). 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)). + Angular registers one of them in the root app injector (see [What if I import the same module twice?](#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!_ + 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. @@ -513,58 +502,57 @@ a#q-why-bad That's almost certainly a mistake. .l-sub-section :marked - Prove it for yourself. - Run the live example. + To demonstrate, 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? + ## 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. + Angular adds `@NgModule.providers` to the application root injector, unless the module is lazy loaded. + For a lazy-loaded module, Angular 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 + This means that a module behaves differently depending on whether it's 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? + Why doesn't Angular add lazy-loaded providers to the app root injector as it does for eagerly loaded modules? - 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. + The answer is grounded in a fundamental characteristic of the Angular dependency-injection system. + An injector can add providers _until it's first used_. + Once an injector starts creating and delivering services, its provider list is frozen; no new providers are 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_. + Time passes and 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. + 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? + ## 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`. + Some modules and their services should be loaded only 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 + To prevent this issue, write 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. + You 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. + Certain NgModules (such as `BrowserModule`) implement such a guard, + such as this `CoreModule` constructor from the NgModules page. +makeExample('ngmodule/ts/src/app/core/core.module.ts', 'ctor', 'src/app/core/core.module.ts (Constructor)')(format='.') :marked @@ -573,26 +561,26 @@ a#q-is-it-loaded a#q-entry-component-defined .l-main-section :marked - ### What is an _entry component_? + ## What is an _entry component_? - Any component that Angular loads _imperatively_ by type is an _entry component_, + An entry component is any component that Angular loads _imperatively_ by type. 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. + These aren't 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` + But `index.html` isn't 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. + Angular loads `AppComponent` dynamically because it's either listed _by type_ in `@NgModule.bootstrap` + or boostrapped 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_. @@ -600,37 +588,37 @@ a#q-entry-component-defined 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. + You 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 + Angular automatically adds the following types of components to the module's `entryComponents`: + * The component in the `@NgModule.bootstrap` list. + * Components referenced in router configuration. - We don't have to mention these components explicitly although it does not harm to do so. + You don't have to mention these components explicitly, although doing so is harmless. .l-hr a#q-bootstrap_vs_entry_component .l-main-section :marked - ### What's the difference between a _bootstrap_ component and an _entry component_? + ## 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. + A bootstrapped component _is_ an [entry component](#q-entry-component-defined) + 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. + The `@NgModule.bootstrap` property tells the compiler that this is an entry component _and_ + 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. + There's no need to list a component in both the `bootstrap` and `entryComponent` lists, + although doing so is harmless. .l-hr a#q-when-entry-components .l-main-section :marked - ### When do I add components to _entryComponents_? + ## When do I add components to _entryComponents_? Most application developers won't need to add components to the `entryComponents`. @@ -640,7 +628,7 @@ a#q-when-entry-components 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. + you must 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_. @@ -652,28 +640,27 @@ a#q-when-entry-components a#q-why-entry-components .l-main-section :marked - ### Why does Angular need _entryComponents_? + ## 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. + Then you 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. + The reason is _tree shaking_. For production apps you want to load the smallest, fastest code possible. + The code should contain only the classes that you 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. + In fact, many libraries declare and export components you'll never use. + If you don't reference them, the tree shaker drops these components from the final code package. 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. + Instead, the compiler adopts a recursive strategy that generates code only for the components you use. - It starts with the entry components, + The compiler 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 so on. At the end of the process, the compiler 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, @@ -685,62 +672,62 @@ a#q-why-entry-components a#q-module-recommendations .l-main-section :marked - #### What kinds of modules should I have and how should I use them? + ## 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. + Every app is different. Developers have various 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. + The following is preliminary guidance based on early experience using NgModules in a few applications. Read with appropriate caution and reflection. :marked - #### _SharedModule_ + ### _SharedModule_ Create a `SharedModule` with the components, directives, and pipes that you use - everywhere in your app. This module should consist entirely of `declarations` + 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. + The `SharedModule` 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). + The `SharedModule` should *not* have `providers` for reasons [explained previously](#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. + If you deviate from this guideline, know what you're doing and why. Import the `SharedModule` in your _feature_ modules, both those loaded when the app starts and those you lazy load later. - #### _CoreModule_ + ### _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`. + Never import `CoreModule` in any other module. 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 + This page 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 + Create feature modules around specific application business domains, user workflows, and utility collections. - Feature modules tend to fall into one of these five groups: - * [Domain Feature Modules](#domain-feature-module) - * [Routed Feature Modules](#routed-feature-module) - * [Routing Modules](#routing-module) - * [Service Feature Modules](#service-feature-module) - * [Widget Feature Modules](#widget-feature-module) + Feature modules tend to fall into one of the following groups: + * [Domain feature modules](#domain-feature-module). + * [Routed feature modules](#routed-feature-module). + * [Routing modules](#routing-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. + Real-world modules are often hybrids that purposefully deviate from the following guidelines. + These guidelines are not laws; + follow them unless you have a good reason to do otherwise. table tr @@ -750,20 +737,20 @@ table td(style="vertical-align: top")Domain td :marked - Domain Feature Modules deliver a user experience **dedicated to a particular application domain** + 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_. + Domain feature modules 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. + Don't provide application-wide singleton services in a domain feature module. Domain feature modules are typically imported _exactly once_ by a larger feature module. @@ -771,107 +758,108 @@ table .l-sub-section :marked - For an example, see [_ContactModule_](../guide/ngmodule.html#contact-module-v1) - in the Angular Module chapter, before we introduced routing. + For an example, see the [Make _Contact_ a feature module](../guide/ngmodule.html#contact-module-v1) + section of the [NgModules](../guide/ngmodule.html) page, before routing is introduced. 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**. + _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 definition. + All lazy-loaded modules are routed feature modules by definition. - This chapter's `ContactModule`, `HeroModule` and `CrisisModule` are routed feature modules. + This page'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 _shouldn't export anything_. + They don't have to because their components never appear in the template of an external component. - A lazy loaded Routed Feature Module should _not be imported_ by any module. + A lazy-loaded routed feature module should _not be imported_ by any module. Doing so would trigger an eager load, defeating the purpose of lazy loading. `HeroModule` and `CrisisModule` are lazy loaded. They aren't mentioned among the `AppModule` imports. - But an eager loaded Routed Feature Module must be imported by another module + But an eager loaded routed feature module must be imported by another module so that the compiler learns about its components. - `ContactModule` is eager loaded and, therefore, is listed among the `AppModule` imports. + `ContactModule` is eager loaded and therefore listed among the `AppModule` imports. 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 + Don't 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")Routing td :marked - A [_Routing Module_](../guide/router.html#routing-module) **provides routing configuration** for another module. + A [routing module](../guide/router.html#routing-module) *provides routing configuration* for another module. - A Routing Module separates routing concerns from its companion module. + A routing module separates routing concerns from its companion module. - It typically: - * defines routes - * adds router configuration to the module's `imports` - * re-exports `RouterModule` - * adds guard and resolver service providers to the module's `providers`. + A routing module typically does the following: + * Defines routes. + * Adds router configuration to the module's `imports`. + * Re-exports `RouterModule`. + * Adds guard and resolver service providers to the module's `providers`. - The name of the Routing Module should parallel the name of its companion module, using the suffix "Routing". + The name of the routing module should parallel the name of its companion module, using the suffix "Routing". For example, `FooModule` in `foo.module.ts` has a routing module named `FooRoutingModule` in `foo-routing.module.ts` If the companion module is the _root_ `AppModule`, the `AppRoutingModule` adds router configuration to its `imports` with `RouterModule.forRoot(routes)`. - All other Routing Modules are children that import `RouterModule.forChild(routes)`. + All other routing modules are children that import `RouterModule.forChild(routes)`. - A Routing Module re-exports the `RouterModule` as a convenience + A routing module re-exports the `RouterModule` as a convenience so that components of the companion module have access to router directives such as `RouterLink` and `RouterOutlet`. - A Routing Module **should not have its own `declarations`!** -   Components, directives, and pipes are the **responsibility of the feature module** + A routing module *should not have its own `declarations`*. +   Components, directives, and pipes are the *responsibility of the feature module*, not the _routing_ module. - A Routing Module should _only_ be imported by its companion module. + A routing module should _only_ be imported by its companion module. - The `AppRoutingModule`, `ContactRoutingModule` and `HeroRoutingModule` are good examples. + The `AppRoutingModule`, `ContactRoutingModule`, and `HeroRoutingModule` are good examples. .l-sub-section :marked - See also "[Do you need a _Routing Module_?](../guide/router.html#why-routing-module)". + See also [Do you need a _Routing Module_?](../guide/router.html#why-routing-module) on the + [Routing & Navigation](../guide/router.html) page. tr td(style="vertical-align: top")Service td :marked - _Service Modules_ **provide utility services** such as data access and messaging. + Service modules *provide utility services* such as data access and messaging. - Ideally they consist entirely of _providers_ and have no _declarations_. + 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. + Do *not* import service modules in other feature modules. + If you deviate from this guideline, know what you're doing and why. tr td(style="vertical-align: top")Widget td :marked - A _Widget Module_ makes **components, directives, and pipes** available to external modules. + 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. + 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 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. + A widget module should rarely have _providers_. + If you deviate from this guideline, know what you're doing and why. - Import Widget Modules in any module whose component templates need the widgets. + 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. + 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. + Real-world modules are often hybrids that knowingly deviate from these guidelines. table tr th Feature Module @@ -884,7 +872,7 @@ table td Domain td Yes td Rare - td Top Component + td Top component td Feature, AppModule td ContactModule (before routing) tr @@ -921,18 +909,19 @@ table a#q-ng-vs-js-modules .l-main-section :marked - ### What's the difference between Angular and JavaScript Modules? + ## What's the difference between Angular and JavaScript Modules? - Angular and JavaScript are two different yet complementary module systems. + Angular and JavaScript are 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: + In modern JavaScript, every file is a _module_ + (see the [Modules](http://exploringjs.com/es6/ch_modules.html) page of the Exploring ES6 website). + Within each file you 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: + Then you `import` a part in another module: code-example(format='.'). import { AppComponent } from './app.component'; @@ -940,55 +929,54 @@ code-example(format='.'). :marked This kind of modularity is a feature of the _JavaScript language_. - An _Angular Module_ is a feature of _Angular_ itself. + An _NgModule_ 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. + You _import_ other NgModules so you can use their exported classes in component templates. + You _export_ this NgModule'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: + The NgModule classes differ from JavaScript module class in the following key ways: - 1. An Angular module bounds [_declarable classes_](#q-declarables) only. + * An NgModule bounds [declarable classes](#q-declarable) 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) + * Instead of defining all member classes in one giant file (as in a JavaScript module), + you list the module's classes in the `@NgModule.declarations` list. + * An NgModule can only export the [declarable classes](#q-declarable) 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 + The NgModule is also special in another way. + Unlike JavaScript modules, an NgModule 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. + The provided services don't 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. + Here's an _NgModule_ class with imports, exports, and declarations. +makeExample('ngmodule/ts/src/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: + Of course you use _JavaScript_ modules to write _Angular_ modules as seen in the complete `contact.module.ts` file: +makeExample('ngmodule/ts/src/app/contact/contact.module.2.ts', '', 'src/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 + ## How does Angular find components, directives, and pipes in a template?
What is a template reference? + 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 + 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. + 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. @@ -998,27 +986,27 @@ h4. a#q-angular-compiler .l-main-section :marked - ### What is the Angular Compiler? + ## What is the Angular compiler? - The _Angular Compiler_ converts the application code we write into highly performant JavaScript code. + The Angular compiler converts the application code you 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**. + The code you write isn't 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, + 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. + the HTML, the binding instructions, the attached styles. - Because **directives** and **pipes** appear in component templates, - the _Angular Compiler_ incorporates them into compiled component code too. + 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 + `@NgModule` metadata tells the Angular compiler what components to compile for this module and how to link this module with other modules. .l-hr @@ -1026,9 +1014,9 @@ a#q-angular-compiler a#q-ngmodule-api .l-main-section :marked - ## *NgModule* API + ## NgModule API - The following chart summarizes the `NgModule` metadata properties. + The following table summarizes the `NgModule` metadata properties. // export interface NgModuleMetadataType { providers?: any[]; @@ -1048,37 +1036,37 @@ table 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_. + A list of [declarable](#q-declarable) 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 in a different module unless they are _exported_ from this module and + the 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. + Components, directives, and pipes must belong to _exactly_ one module. + The compiler emits an error if you try to declare the same class in more than one module. - **Do not re-declare a class imported from another 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. + 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`, + If this module 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 + 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) + 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 (such as by router navigation) gets the local instance of the service, not the instance in the root application injector. Components in external modules continue to receive the instance created for the application root. @@ -1089,29 +1077,29 @@ table :marked A list of supporting modules. - Specifically, the list of modules whose exported components, directives or pipes + 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 + A component template can [reference](#q-template-reference) another component, directive, or pipe + when 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. + You 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 + 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`. + if it imports this module and this module exports `HeroComponent`. Declarations are private by default. If this module does _not_ export `HeroComponent`, no other module can see it. @@ -1120,7 +1108,7 @@ table 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 + 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. @@ -1133,12 +1121,12 @@ table :marked A list of components that can be bootstrapped. - Usually there is only one component in this list, the _root component_ of the application. + Usually there's 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` + A bootstrap component is automatically an `entryComponent`. tr td(style="vertical-align: top") entryComponents @@ -1146,29 +1134,28 @@ table :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. + Most developers never set this property. + 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. + But there's always at least one component that's not referenced in any template: + the root component, `AppComponent`, that you 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 usually don't have to add them to a module's `entryComponents` list. + you usually 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. + That leaves only the following sources of undiscoverable components: + * Components bootstrapped using one of the imperative techniques. + * 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 + Both are advanced techniques that few developers ever employ. + If you are one of those few, you must add these components to the `entryComponents` list yourself, either programmatically or by hand. diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index b3d738527e..e4a055b5ac 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -101,11 +101,6 @@ "basics": true }, - "ngmodule": { - "title": "Angular Modules (NgModule)", - "intro": "Define application modules with @NgModule" - }, - "animations": { "title": "Animations", "intro": "A guide to Angular's animation system." @@ -152,6 +147,11 @@ "intro": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them." }, + "ngmodule": { + "title": "NgModules", + "intro": "Define application modules with @NgModule." + }, + "npm-packages": { "title": "Npm Packages", "intro": "Recommended npm packages, and how to specify package dependencies" diff --git a/public/docs/ts/latest/guide/forms.jade b/public/docs/ts/latest/guide/forms.jade index 6c7a59ec22..1c36b14f13 100644 --- a/public/docs/ts/latest/guide/forms.jade +++ b/public/docs/ts/latest/guide/forms.jade @@ -26,13 +26,13 @@ include ../_util-fns Run the . -.l-main-section +.l-main-section#template-driven :marked ## Template-driven forms Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with the form-specific directives and techniques described in this guide. - + .l-sub-section :marked That's not the only way to create a form but it's the way we'll cover in this guide. diff --git a/public/docs/ts/latest/guide/ngmodule.jade b/public/docs/ts/latest/guide/ngmodule.jade index c61ff30533..23d4359e38 100644 --- a/public/docs/ts/latest/guide/ngmodule.jade +++ b/public/docs/ts/latest/guide/ngmodule.jade @@ -3,42 +3,53 @@ block includes // TODO Images - + :marked - **Angular Modules** help organize an application into cohesive blocks of functionality. + **NgModules** help organize an application into cohesive blocks of functionality. + - An Angular Module is a _class_ adorned with the **@NgModule** decorator function. + An NgModule is a class adorned with the *@NgModule* decorator function. `@NgModule` takes a metadata object that tells Angular how to compile and run module code. - It identifies the module's _own_ components, directives and pipes, + It identifies the module's own components, directives, and pipes, making some of them public so external components can use them. - It may add service providers to the application dependency injectors. + `@NgModule` may add service providers to the application dependency injectors. And there are many more options covered here. - [The Root Module](appmodule.html) guide introduced Angular Modules and the essentials - of creating and maintaining a single _root_ `AppModule` for the entire application. - Read that first. + Before reading this page, read the + [The Root Module](appmodule.html) page, which introduces NgModules and the essentials + of creating and maintaining a single root `AppModule` for the entire application. - This page goes into Angular modules in much greater depth. + This page covers NgModules in greater depth. ## Table of Contents + * [Angular modularity](#angular-modularity "Add structure to the app with NgModule") * [The application root module](#root-module "The startup module that every app requires") * [Bootstrap](#bootstrap "Launch the app in a browser with the root module as the entry point") the root module * [Declarations](#declarations "Declare the components, directives, and pipes that belong to a module") * [Providers](#providers "Extend the app with additional services") * [Imports](#imports "Import components, directives, and pipes for use in component templates") - * [Resolve conflicts](#resolve-conflicts "When two directives have the same selector ...") + * [Resolve conflicts](#resolve-conflicts "When two directives have the same selector") + * [Feature modules](#feature-modules "Partition the app into feature modules") - * [Lazy loaded modules](#lazy-load "Load modules asynchronously") with the Router + * [Lazy loaded modules](#lazy-load "Load modules asynchronously") with the router * [Shared modules](#shared-module "Create modules for commonly used components, directives, and pipes") * [The Core module](#core-module "Create a core module with app-wide singleton services and single-use components") * [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") + ### Live examples - This page explains Angular Modules through a progression of improvements to a sample with a "Tour of Heroes" theme. - Here's an index to live examples at key moments in the evolution of that sample: + This page explains NgModules through a progression of improvements to a sample with a "Tour of Heroes" theme. + Here's an index to live examples at key moments in the evolution of the sample: * A minimal NgModule app * The first contact module @@ -46,97 +57,97 @@ block includes * Just before adding _SharedModule_ * The final version - ### Frequently Asked Questions (FAQs) + ### Frequently asked questions (FAQs) - This page covers Angular Module concepts in a tutorial fashion. + This page covers NgModule 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 page first before hopping over to those FAQs. + The companion [NgModule FAQs](../cookbook/ngmodule-faq.html "NgModule FAQs") cookbook + offers answers to specific design and implementation questions. + Read this page before reading those FAQs. .l-hr a#angular-modularity .l-main-section :marked - ## Angular Modularity + ## Angular modularity - Modules are a great way to organize the application and extend it with capabilities from external libraries. + Modules are a great way to organize an application and extend it with capabilities from external libraries. - Many Angular libraries are modules (e.g, `FormsModule`, `HttpModule`, `RouterModule`). - Many third party libraries are available as Angular modules (e.g., + Many Angular libraries are modules (such as `FormsModule`, `HttpModule`, and `RouterModule`). + Many third-party libraries are available as NgModules (such as Material Design, Ionic, AngularFire2). - Angular modules consolidate components, directives and pipes into + NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities. Modules can also add services to the application. - Such services might be internally-developed such as the application logger. - They can come from outside sources such as the Angular router and Http client. + Such services might be internally developed, such as the application logger. + Services can come from outside sources, such as the Angular router and Http client. Modules can be loaded eagerly when the application starts. They can also be _lazy loaded_ asynchronously by the router. - An Angular module is a class decorated with `@NgModule` metadata. The metadata: + An NgModule is a class decorated with `@NgModule` metadata. The metadata do the following: - * declare which components, directives and pipes _belong_ to the module. - * make some of those classes public so that other component templates can use them. - * import other modules with the components, directives and pipes needed by the components in _this_ module. - * provide services at the application level that any application component can use. + * Declare which components, directives, and pipes belong to the module. + * Make some of those classes public so that other component templates can use them. + * Import other modules with the components, directives, and pipes needed by the components in _this_ module. + * Provide services at the application level that any application component can use. Every Angular app has at least one module class, the _root module_. - We bootstrap that module to launch the application. + You bootstrap that module to launch the application. - The _root module_ is all we need in a simple application with a few components. - As the app grows, we refactor the _root module_ into **feature modules** + The root module is all you need in a simple application with a few components. + As the app grows, you refactor the root module into *feature modules* that represent collections of related functionality. - We then import these modules into the _root module_. + You then import these modules into the root module. - We'll see how later in the page. Let's start with the _root module_. + Later in this page, you'll read about this process. For now, you'll start with the root module. a#root-module .l-main-section :marked - ## _AppModule_ - the application root module + ## _AppModule_: the application root module - Every Angular app has a **root module** class. - By convention it's a class called `AppModule` in a file named `app.module.ts`. + Every Angular app has a *root module* class. + By convention, the *root module* class is called `AppModule` and it exists in a file named `app.module.ts`. - The `AppModule` from the [_QuickStart seed_](setup.html) is about as minimal as it gets: + The `AppModule` from the QuickStart seed on the [Setup](setup.html) page is as minimal as possible: +makeExample('setup/ts/src/app/app.module.ts', '', 'src/app/app.module.ts (minimal)')(format=".") :marked The `@NgModule` decorator defines the metadata for the module. - We'll take an intuitive approach to understanding the metadata and fill in details as we go. + This page takes an intuitive approach to understanding the metadata and fills in details as it progresses. - This metadata imports a single helper module, `BrowserModule`, the module every browser app must import. + The metadata imports a single helper module, `BrowserModule`, which every browser app must import. `BrowserModule` registers critical application service providers. - It also includes common directives like `NgIf` and `NgFor` which become immediately visible and usable - in any of this modules component templates. + It also includes common directives like `NgIf` and `NgFor`, which become immediately visible and usable + in any of this module's component templates. The `declarations` list identifies the application's only component, - the _root component_, the top of this app's rather bare component tree. + the _root component_, the top of the app's rather bare component tree. The example `AppComponent` simply displays a data-bound title: +makeExample('ngmodule/ts/src/app/app.component.0.ts', '', 'src/app/app.component.ts (minimal)')(format=".") :marked Lastly, the `@NgModule.bootstrap` property identifies this `AppComponent` as the _bootstrap component_. When Angular launches the app, it places the HTML rendering of `AppComponent` in the DOM, - inside the `` element tags of the `index.html` + inside the `` element tags of the `index.html`. a#bootstrap .l-main-section :marked ## Bootstrapping in _main.ts_ - We launch the application by bootstrapping the `AppModule` in the `main.ts` file. + You launch the application by bootstrapping the `AppModule` in the `main.ts` file. - Angular offers a variety of bootstrapping options, targeting multiple platforms. - In this page we consider two options, both targeting the browser. + Angular offers a variety of bootstrapping options targeting multiple platforms. + This page describes two options, both targeting the browser. - ### Dynamic bootstrapping with the Just-in-time (JIT) compiler + ### Dynamic bootstrapping with the just-in-time (JIT) 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. @@ -147,12 +158,12 @@ a#bootstrap Try the live example. - ### Static bootstrapping with the Ahead-Of-time (AOT) compiler + ### Static bootstrapping with the ahead-of-time (AOT) compiler Consider the static alternative which can produce a much smaller application that launches faster, especially on mobile devices and high latency networks. - In the _static_ option, the Angular compiler runs ahead-of-time as part of the build process, + In the _static_ option, the Angular compiler runs ahead of time as part of the build process, producing a collection of class factories in their own files. Among them is the `AppModuleNgFactory`. @@ -162,21 +173,21 @@ a#bootstrap +makeExample('ngmodule/ts/src/main-static.ts', '', 'src/main.ts (static)')(format=".") :marked Because the entire application was pre-compiled, - we don't ship the _Angular Compiler_ to the browser and we don't compile in the browser. + Angular doesn't ship the Angular compiler to the browser and doesn't compile in the browser. The application code downloaded to the browser is much smaller than the dynamic equivalent - and it is ready to execute immediately. The performance boost can be significant. + and it's ready to execute immediately. The performance boost can be significant. Both the JIT and AOT compilers generate an `AppModuleNgFactory` class from the same `AppModule` source code. The JIT compiler creates that factory class on the fly, in memory, in the browser. The AOT compiler outputs the factory to a physical file - that we're importing here in the static version of `main.ts`. + that is imported here in the static version of `main.ts`. In general, the `AppModule` should neither know nor care how it is bootstrapped. Although the `AppModule` evolves as the app grows, the bootstrap code in `main.ts` doesn't change. - This is the last time we'll look at `main.ts`. + This is the last time you'll look at `main.ts`. .l-hr @@ -184,16 +195,16 @@ a#declarations .l-main-section :marked ## Declare directives and components - The app evolves. - The first addition is a `HighlightDirective`, an [attribute directive](attribute-directives.html) + As the app evolves, + the first addition is a `HighlightDirective`, an [attribute directive](attribute-directives.html) that sets the background color of the attached element. +makeExample('ngmodule/ts/src/app/highlight.directive.ts', '', 'src/app/highlight.directive.ts')(format=".") :marked - We update the `AppComponent` template to attach the directive to the title: + Update the `AppComponent` template to attach the directive to the title: +makeExample('ngmodule/ts/src/app/app.component.1.ts', 'template')(format=".") :marked - If we ran the app now, Angular would not recognize the `highlight` attribute and would ignore it. - We must declare the directive in `AppModule`. + If you ran the app now, Angular wouldn't recognize the `highlight` attribute and would ignore it. + You must declare the directive in `AppModule`. Import the `HighlightDirective` class and add it to the module's `declarations` like this: +makeExample('ngmodule/ts/src/app/app.module.1.ts', 'directive')(format=".") @@ -201,30 +212,30 @@ a#declarations :marked ### Add a component - We decide to refactor the title into its own `TitleComponent`. + Refactor the title into its own `TitleComponent`. The component's template binds to the component's `title` and `subtitle` properties like this: +makeExample('ngmodule/ts/src/app/title.component.html', 'v1', 'src/app/title.component.html')(format=".") +makeExample('ngmodule/ts/src/app/title.component.ts', 'v1', 'src/app/title.component.ts')(format=".") :marked - We rewrite the `AppComponent` to display the new `TitleComponent` in the `` element, + Rewrite the `AppComponent` to display the new `TitleComponent` in the `` element, using an input binding to set the `subtitle`. +makeExample('ngmodule/ts/src/app/app.component.1.ts', '', 'src/app/app.component.ts (v1)')(format=".") :marked - Angular won't recognize the `` tag until we declare it in `AppModule`. + Angular won't recognize the `` tag until you declare it in `AppModule`. Import the `TitleComponent` class and add it to the module's `declarations`: +makeExample('ngmodule/ts/src/app/app.module.1.ts', 'component')(format=".") a#providers .l-main-section :marked - ## Service Providers + ## Service providers Modules are a great way to provide services for all of the module's components. The [Dependency Injection](dependency-injection.html) page describes - the Angular hierarchical dependency injection system and how to configure that system + the Angular hierarchical dependency-injection system and how to configure that system with [providers](dependency-injection.html#providers) at different levels of the application's component tree. @@ -237,7 +248,7 @@ a#providers +makeExample('ngmodule/ts/src/app/user.service.ts', '', 'src/app/user.service.ts')(format=".") :marked - The sample application should display a welcome message to the logged in user just below the application title. + The sample application should display a welcome message to the logged-in user just below the application title. Update the `TitleComponent` template to show the welcome message below the application title. +makeExample('ngmodule/ts/src/app/title.component.html', '', 'src/app/title.component.html')(format=".") :marked @@ -245,8 +256,8 @@ a#providers and sets the component's `user` property from the service. +makeExample('ngmodule/ts/src/app/title.component.ts', '', 'src/app/title.component.ts')(format=".") :marked - We've _defined_ and _used_ the service. Now we _provide_ it for all components to use by - adding it to a `providers` property in the `AppModule` metadata: + You've defined and used the service. Now to _provide_ it for all components to use, + add it to a `providers` property in the `AppModule` metadata: +makeExample('ngmodule/ts/src/app/app.module.1.ts', 'providers', 'src/app/app.module.ts (providers)')(format=".") a#imports @@ -254,69 +265,67 @@ a#imports :marked ## Import supporting modules - The app shouldn't welcome a user if there is no user. - - Notice in the revised `TitleComponent` that an `*ngIf` directive guards the message. + In the revised `TitleComponent`, an `*ngIf` directive guards the message. There is no message if there is no user. +makeExample('ngmodule/ts/src/app/title.component.html', 'ngIf', 'src/app/title.component.html (ngIf)')(format=".") :marked Although `AppModule` doesn't declare `NgIf`, the application still compiles and runs. How can that be? The Angular compiler should either ignore or complain about unrecognized HTML. - Angular _does_ recognize `NgIf` because we imported it earlier. + Angular does recognize `NgIf` because you imported it earlier. The initial version of `AppModule` imports `BrowserModule`. +makeExample('ngmodule/ts/src/app/app.module.0.ts', 'imports', 'src/app/app.module.ts (imports)')(format=".") :marked - Importing `BrowserModule` made all of its public components, directives and pipes visible - to the component templates in `AppModule`. They are ready to use without further ado. + Importing `BrowserModule` made all of its public components, directives, and pipes visible + to the component templates in `AppModule`. .l-sub-section :marked More accurately, `NgIf` is declared in `CommonModule` from `@angular/common`. - `CommonModule` contributes many of the common directives that applications need including `ngIf` and `ngFor`. + `CommonModule` contributes many of the common directives that applications need, including `ngIf` and `ngFor`. - `BrowserModule` imports `CommonModule` and [_re-exports_](../cookbook/ngmodule-faq.html#q-re-export) it. + `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`. + Many familiar Angular directives don't belong to `CommonModule`. For example, `NgModel` and `RouterLink` belong to Angular's `FormsModule` and `RouterModule` respectively. - We must _import_ those modules before we can use their directives. + You must import those modules before you can use their directives. - To illustrate this point, we extend the sample app with `ContactComponent`, + To illustrate this point, you'll extend the sample app with `ContactComponent`, a form component that imports form support from the Angular `FormsModule`. ### Add the _ContactComponent_ - [Angular Forms](forms.html) are a great way to manage user data entry. + [Angular forms](forms.html) are a great way to manage user data entry. - The `ContactComponent` presents a "contact editor", - implemented with _Angular Forms_ in the [_template-driven form_](forms.html) style. + The `ContactComponent` presents a "contact editor," + implemented with Angular forms in the [template-driven form](forms.html#template-driven) style. .l-sub-section :marked - ### Angular Form Styles + ### Angular form styles - We write Angular form components in either the - [_template-driven form_](forms.html) style or - the [_reactive form_](../cookbook/dynamic-form.html) style. + You can write Angular form components in + template-driven or + [reactive](../cookbook/dynamic-form.html) style. + - This sample is about to import the `FormsModule` from `@angular/forms` because - the `ContactComponent` is written in the _template-driven_ style. - Modules with components written in the _reactive_ style, - should import the `ReactiveFormsModule` instead. + The following sample imports the `FormsModule` from `@angular/forms` because + the `ContactComponent` is written in _template-driven_ style. + Modules with components written in the _reactive_ style + import the `ReactiveFormsModule`. :marked The `ContactComponent` selector matches an element named ``. - Add an element with that name to the `AppComponent` template just below the ``: + Add an element with that name to the `AppComponent` template, just below the ``: +makeExample('ngmodule/ts/src/app/app.component.1b.ts', 'template', 'src/app/app.component.ts (template)')(format=".") :marked - The `ContactComponent` has a lot going on. - Form components are often complex anyway and this one has its own `ContactService`, - its own [custom pipe](#pipes.html#custom-pipes) called `Awesome`, + Form components are often complex. The `ContactComponent` has its own `ContactService` + and [custom pipe](pipes.html#custom-pipes) (called `Awesome`), and an alternative version of the `HighlightDirective`. - To make it manageable, we place all contact-related material in an `src/app/contact` folder + To make it manageable, place all contact-related material in an `src/app/contact` folder and break the component into three constituent HTML, TypeScript, and css files: +makeTabs( `ngmodule/ts/src/app/contact/contact.component.html, @@ -335,40 +344,41 @@ a#imports src/app/contact/highlight.directive.ts `) :marked - Focus on the component template. - Notice the two-way data binding `[(ngModel)]` in the middle of the template. + In the middle of the component template, + notice the two-way data binding `[(ngModel)]`. `ngModel` is the selector for the `NgModel` directive. - Although `NgModel` is an Angular directive, the _Angular Compiler_ won't recognize it - because (a) `AppModule` doesn't declare it and (b) it wasn't imported via `BrowserModule`. + Although `NgModel` is an Angular directive, the _Angular compiler_ won't recognize it for the following reasons: + * `AppModule` doesn't declare `NgModel`. + * `NgModel` wasn't imported via `BrowserModule`. - Less obviously, even if Angular somehow recognized `ngModel`, - this `ContactComponent` would not behave like an Angular form because - form features such as validation are not yet available. + Even if Angular somehow recognized `ngModel`, + `ContactComponent` wouldn't behave like an Angular form because + form features such as validation aren't yet available. ### Import the FormsModule Add the `FormsModule` to the `AppModule` metadata's `imports` list. +makeExample('ngmodule/ts/src/app/app.module.1.ts', 'imports')(format=".") :marked - Now `[(ngModel)]` binding will work and the user input will be validated by Angular Forms, - once we declare our new component, pipe and directive. + Now `[(ngModel)]` binding will work and the user input will be validated by Angular forms, + once you declare the new component, pipe, and directive. .alert.is-critical :marked - **Do not** add `NgModel` — or the `FORMS_DIRECTIVES` — - to the `AppModule` metadata's declarations! - + *Do not* add `NgModel`—or the `FORMS_DIRECTIVES`—to + the `AppModule` metadata's declarations. These directives belong to the `FormsModule`. - Components, directives and pipes belong to one module — and _one module only_. + + Components, directives, and pipes belong to _one module only_. - **Never re-declare classes that belong to another module.** + *Never re-declare classes that belong to another module.* a#declare-pipe :marked - ### Declare the contact component, directive and pipe + ### Declare the contact component, directive, and pipe - The application fails to compile until we declare the contact component, directive and pipe. + The application won't compile until you declare the contact component, directive, and pipe. Update the `declarations` in the `AppModule` accordingly: +makeExample('ngmodule/ts/src/app/app.module.1.ts', 'declarations', 'src/app/app.module.ts (declarations)')(format=".") @@ -377,56 +387,57 @@ a#import-name-conflict :marked There are two directives with the same name, both called `HighlightDirective`. - We work around it by creating an alias for the second, contact version using the `as` JavaScript import keyword: + To work around this, create an alias for the contact version using the `as` JavaScript import keyword. +makeExample('ngmodule/ts/src/app/app.module.1b.ts', 'import-alias')(format=".") :marked - This solves the immediate problem of referencing both directive _types_ in the same file but - leaves another problem unresolved as we discuss [below](#resolve-conflicts). + This solves the immediate issue of referencing both directive _types_ in the same file but + leaves another issue unresolved. + You'll learn more about that issue later in this page, in [Resolve directive conflicts](#resolve-conflicts). :marked ### Provide the _ContactService_ - The `ContactComponent` displays contacts retrieved by the `ContactService` + The `ContactComponent` displays contacts retrieved by the `ContactService`, which Angular injects into its constructor. - We have to provide that service somewhere. - The `ContactComponent` _could_ provide it. - But then it would be scoped to this component _only_. - We want to share this service with other contact-related components that we will surely add later. + You have to provide that service somewhere. + The `ContactComponent` could provide it, + but then the service would be scoped to this component only. + You want to share this service with other contact-related components that you'll surely add later. - In this app we chose to add `ContactService` to the `AppModule` metadata's `providers` list: + In this app, add `ContactService` to the `AppModule` metadata's `providers` list: +makeExample('ngmodule/ts/src/app/app.module.1b.ts', 'providers', 'src/app/app.module.ts (providers)')(format=".") :marked - Now `ContactService` (like `UserService`) can be injected into any component in the application. + Now you can inject `ContactService` (like `UserService`) into any component in the application. a#application-scoped-providers .l-sub-section :marked - ### Application-scoped Providers + ### Application-scoped providers The `ContactService` provider is _application_-scoped because Angular - registers a module's `providers` with the application's **root injector**. + registers a module's `providers` with the application's *root injector*. Architecturally, the `ContactService` belongs to the Contact business domain. - Classes in _other_ domains don't need the `ContactService` and shouldn't inject it. + Classes in other domains don't need the `ContactService` and shouldn't inject it. - We might expect Angular to offer a _module_-scoping mechanism to enforce this design. - It doesn't. Angular module instances, unlike components, do not have their own injectors + You might expect Angular to offer a _module_-scoping mechanism to enforce this design. + It doesn't. NgModule instances, unlike components, don't have their own injectors so they can't have their own provider scopes. This omission is intentional. - Angular modules are designed primarily to extend an application, + NgModules are designed primarily to extend an application, to enrich the entire app with the module's capabilities. - Service scoping is rarely a problem in practice. - Non-contact components can't inject the `ContactService` by accident. + In practice, service scoping is rarely an issue. + Non-contact components can't accidentally inject the `ContactService`. To inject `ContactService`, you must first import its _type_. - Only Contact components should import the `ContactService` _type_. + Only Contact components should import the `ContactService` type. - See the [FAQ that pursues this issue](../cookbook/ngmodule-faq.html#q-component-scoped-providers) - and its mitigations in greater detail. + Read more in the [How do I restrict service scope to a module?](../cookbook/ngmodule-faq.html#q-component-scoped-providers) section + of the [NgModule FAQs](../cookbook/ngmodule-faq.html) page. :marked ### Run the app - Everything is now in place to run the application with its contact editor. + Everything is in place to run the application with its contact editor. The app file structure looks like this: .filetree @@ -452,13 +463,14 @@ a#resolve-conflicts .l-main-section :marked ## Resolve directive conflicts + - We ran into trouble [above](#import-name-conflict) when we declared the contact's `HighlightDirective` because - we already had a `HighlightDirective` class at the application level. + An issue arose [earlier](#import-name-conflict) when you declared the contact's `HighlightDirective` because + you already had a `HighlightDirective` class at the application level. - That both directives have the same name smells of trouble. - - A look at their selectors reveals that they both highlight the attached element with a different color. + The selectors of the two directives both highlight the attached element with a different color. +makeTabs( `ngmodule/ts/src/app/highlight.directive.ts, ngmodule/ts/src/app/contact/highlight.directive.ts`, @@ -467,89 +479,83 @@ a#resolve-conflicts src/app/contact/highlight.directive.ts`) :marked - Will Angular use only one of them? No. - Both directives are declared in this module so _both directives are active_. + Both directives are declared in this module so both directives are active. When the two directives compete to color the same element, - the directive declared later wins because its DOM changes overwrite the first. - In this case, the contact's `HighlightDirective` colors the application title text blue + the directive that's declared later wins because its DOM changes overwrite the first. + In this case, the contact's `HighlightDirective` makes the application title text blue when it should stay gold. .l-sub-section :marked - The real problem is that there are _two different classes_ trying to do the same thing. + The issue is that two different classes are trying to do the same thing. - It's OK to import the _same_ directive class multiple times. + It's OK to import the same directive class multiple times. Angular removes duplicate classes and only registers one of them. - But these are actually two different classes, defined in different files, that happen to have the same name. - - They're not duplicates from Angular's perspective. Angular keeps both directives and + But from Angular's perspective, two different classes, defined in different files, that have the same name + are not duplicates. Angular keeps both directives and they take turns modifying the same HTML element. :marked At least the app still compiles. - If we define two different component classes with the same selector specifying the same element tag, + If you define two different component classes with the same selector specifying the same element tag, the compiler reports an error. It can't insert two components in the same DOM location. - What a mess! - - We can eliminate component and directive conflicts by creating feature modules + To eliminate component and directive conflicts, create feature modules that insulate the declarations in one module from the declarations in another. a#feature-modules .l-main-section :marked - ## Feature Modules + ## Feature modules - This application isn't big yet. But it's already suffering structural problems. - - * The root `AppModule` grows larger with each new application class and shows no signs of stopping. - - * We have conflicting directives. - 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`. + This application isn't big yet, but it's already experiencing structural issues. + * The root `AppModule` grows larger with each new application class. + * There are conflicting directives. + The `HighlightDirective` in the contact re-colors the work done by the `HighlightDirective` declared in `AppModule`. + Also, it colors the application title text when it should color only the `ContactComponent`. * 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. - We mitigate these problems with _feature modules_. + You can resolve these issues with _feature modules_. - ### _Feature Module_ - - A _feature module_ is a class adorned by the `@NgModule` decorator and its metadata, + A feature module is a class adorned by the `@NgModule` decorator and its metadata, just like a root module. Feature module metadata have the same properties as the metadata for a root module. The root module and the feature module share the same execution context. - They share the same dependency injector which means the services in one module + They share the same dependency injector, which means the services in one module are available to all. - There are two significant technical differences: + The modules have the following significant technical differences: - 1. We _boot_ the root module to _launch_ the app; - we _import_ a feature module to _extend_ the app. - - 2. A feature module can expose or hide its implementation from other modules. + * You _boot_ the root module to _launch_ the app; + you _import_ a feature module to _extend_ the app. + * A feature module can expose or hide its implementation from other modules. Otherwise, a feature module is distinguished primarily by its intent. 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. + focused on an application business domain, user workflow, facility (forms, http, routing), + or collection of related utilities. - While we can do everything within the root module, - feature modules help us partition the app into areas of specific interest and purpose. + While you can do everything within the root module, + feature modules help you partition the app into areas of specific interest and purpose. + A feature module collaborates with the root module and with other modules through the services it provides and - the components, directives, and pipes that it chooses to share. + the components, directives, and pipes that it shares. - In the next section, we carve the contact functionality out of the root module + In the next section, you'll carve the contact functionality out of the root module and into a dedicated feature module. ### Make _Contact_ a feature module + It's easy to refactor the contact material into a contact feature module. @@ -558,29 +564,30 @@ a#feature-modules 1. Replace the imported `BrowserModule` with `CommonModule`. 1. Import the `ContactModule` into the `AppModule`. - `AppModule` is the only _existing_ class that changes. But we do add one new file. + `AppModule` is the only existing class that changes. But you do add one new file. ### Add the _ContactModule_ - Here's the new `ContactModule` + Here's the new `ContactModule`: +makeExample('ngmodule/ts/src/app/contact/contact.module.2.ts', '', 'src/app/contact/contact.module.ts') :marked - We copy from `AppModule` the contact-related import statements and the `@NgModule` properties - that concern the contact and paste them in `ContactModule`. + You copy from `AppModule` the contact-related import statements and `@NgModule` properties + that concern the contact, and paste them into `ContactModule`. - We _import_ the `FormsModule` because the contact component needs it. + You _import_ the `FormsModule` because the contact component needs it. .alert.is-important :marked - Modules do not inherit access to the components, directives or pipes that are declared in other modules. + Modules don't inherit access to the components, directives, or pipes that are declared in other modules. 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 in - [an FAQ](../cookbook/ngmodule-faq.html#q-browser-vs-common-module). + You also replaced `BrowserModule` by `CommonModule`, for reasons explained in the + [Should I import BrowserModule or CommonModule?](../cookbook/ngmodule-faq.html#q-browser-vs-common-module) + section of the [NgModule FAQs](../cookbook/ngmodule-faq.html) page. - We _declare_ the contact component, directive, and pipe in the module `declarations`. + You _declare_ the contact component, directive, and pipe in the module `declarations`. - We _export_ the `ContactComponent` so + You _export_ the `ContactComponent` so other modules that import the `ContactModule` can include it in their component templates. All other declared contact classes are private by default. @@ -591,14 +598,15 @@ a#feature-modules ### Refactor the _AppModule_ Return to the `AppModule` and remove everything specific to the contact feature set. - Delete the contact import statements. - Delete the contact declarations and contact providers. - Remove the `FormsModule` from the `imports` list (`AppComponent` doesn't need it). + * Delete the contact import statements. + * Delete the contact declarations and contact providers. + * Delete the `FormsModule` from the `imports` list (`AppComponent` doesn't need it). + Leave only the classes required at the application root level. Then import the `ContactModule` so the app can continue to display the exported `ContactComponent`. - Here's the refactored version of the `AppModule` side-by-side with the previous version. + Here's the refactored version of the `AppModule` along with the previous version. +makeTabs( `ngmodule/ts/src/app/app.module.2.ts, ngmodule/ts/src/app/app.module.1b.ts`, @@ -608,15 +616,15 @@ a#feature-modules :marked ### Improvements :marked - There's a lot to like in the revised `AppModule` + There's a lot to like in the revised `AppModule`. * It does not change as the _Contact_ domain grows. - * It only changes when we add new modules. + * It only changes when you add new modules. * It's simpler: - * Fewer import statements - * No `FormsModule` import - * No contact-specific declarations - * No `ContactService` provider - * No `HighlightDirective` conflict + * Fewer import statements. + * No `FormsModule` import. + * No contact-specific declarations. + * No `ContactService` provider. + * No `HighlightDirective` conflict. Try this `ContactModule` version of the sample. @@ -625,18 +633,18 @@ a#feature-modules a#lazy-load .l-main-section :marked - ## Lazy loading modules with the Router + ## Lazy-loading modules with the router The Heroic Staffing Agency sample app has evolved. - It has two more modules, one for managing the heroes-on-staff and another for matching crises to the heroes. + It has two more modules, one for managing the heroes on staff and another for matching crises to the heroes. Both modules are in the early stages of development. - Their specifics aren't important to the story and we won't discuss every line of code. + Their specifics aren't important to the story and this page doesn't discuss every line of code. .l-sub-section :marked - Examine and download the complete source for this version from the - live example. + Examine and download the complete source for this version from + the live example. :marked - Some facets of the current application merit discussion. + Some facets of the current application merit discussion are as follows: * The app has three feature modules: Contact, Hero, and Crisis. * The Angular router helps users navigate among these modules. @@ -645,19 +653,20 @@ a#lazy-load * `HeroModule` and the `CrisisModule` are lazy loaded. - Let's start at the top with the new `AppComponent` template: + The new `AppComponent` template has a title, three links, and a ``. +makeExample('ngmodule/ts/src/app/app.component.3.ts', 'template', 'src/app/app.component.ts (v3 - Template)')(format='.') :marked - The `` element is gone; we're routing to the _Contact_ page now. + The `` element is gone; you're routing to the _Contact_ page now. The `AppModule` has changed modestly: +makeExample('ngmodule/ts/src/app/app.module.3.ts', '', 'src/app/app.module.ts (v3)') .l-sub-section :marked - Some file names bear a `.3` extension indicating + Some file names bear a `.3` extension that indicates a difference with prior or future versions. - We'll explain differences that matter in due course. + The significant differences will be explained in due course. + :marked The module still imports `ContactModule` so that its routes and components are mounted when the app starts. @@ -665,78 +674,78 @@ a#lazy-load The module does _not_ import `HeroModule` or `CrisisModule`. They'll be fetched and mounted asynchronously when the user navigates to one of their routes. - The significant change from version 2 is the addition of the ***AppRoutingModule*** to the module `imports`. - The `AppRoutingModule` is a [_Routing Module_](../guide/router.html#routing-module) + The significant change from version 2 is the addition of the *AppRoutingModule* to the module `imports`. + The `AppRoutingModule` is a [routing module](../guide/router.html#routing-module) that handles the app's routing concerns. ### App routing +makeExample('ngmodule/ts/src/app/app-routing.module.ts', '', 'src/app/app-routing.module.ts')(format='.') :marked - The router is the subject of [its own page](router.html) so we'll skip lightly over the details and - concentrate on the intersection of Angular modules and routing. + The router is the subject of the [Routing & Navigation](router.html) page, so this section skips many of the details and + concentrates on the intersection of NgModules and routing. - This file defines three routes. + The `app-routing.module.ts` file defines three routes. - The first redirects the empty URL (e.g., `http://host.com/`) - to another route whose path is `contact` (e.g., `http://host.com/contact`). + The first route redirects the empty URL (such as `http://host.com/`) + to another route whose path is `contact` (such as `http://host.com/contact`). The `contact` route isn't defined here. It's defined in the _Contact_ feature's _own_ routing module, `contact-routing.module.ts`. It's standard practice for feature modules with routing components to define their own routes. - We'll get to that file in a moment. + You'll get to that file in a moment. The remaining two routes use lazy loading syntax to tell the router where to find the modules: +makeExample('ngmodule/ts/src/app/app-routing.module.ts', 'lazy-routes')(format='.') .l-sub-section :marked - A lazy loaded module location is a _string_, not a _type_. + A lazy-loaded module location is a _string_, not a _type_. In this app, the string identifies both the module _file_ and the module _class_, the latter separated from the former by a `#`. :marked ### RouterModule.forRoot - The `forRoot` static class method of the `RouterModule` with the provided configuration, + The `forRoot` static class method of the `RouterModule` with the provided configuration and added to the `imports` array provides the routing concerns for the module. +makeExample('ngmodule/ts/src/app/app-routing.module.ts', 'forRoot')(format='.') :marked The returned `AppRoutingModule` class is a `Routing Module` containing both the `RouterModule` directives - and the Dependency Injection providers that produce a configured `Router`. + and the dependency-injection providers that produce a configured `Router`. - This `AppRoutingModule` is intended for the app _root_ module _only_. + This `AppRoutingModule` is intended for the app _root_ module only. .alert.is-critical :marked - Never call `RouterModule.forRoot` in a feature routing module. + Never call `RouterModule.forRoot` in a feature-routing module. :marked - Back in the root `AppModule`, we add the `AppRoutingModule` to its `imports` list, + Back in the root `AppModule`, add the `AppRoutingModule` to its `imports` list, and the app is ready to navigate. +makeExample('ngmodule/ts/src/app/app.module.3.ts', 'imports', 'src/app/app.module.ts (imports)')(format='.') :marked ### Routing to a feature module The `src/app/contact` folder holds a new file, `contact-routing.module.ts`. - It defines the `contact` route we mentioned a bit earlier and also provides a `ContactRoutingModule` like so: + It defines the `contact` route mentioned earlier and provides a `ContactRoutingModule` as follows: +makeExample('ngmodule/ts/src/app/contact/contact-routing.module.ts', 'routing', 'src/app/contact/contact-routing.module.ts (routing)')(format='.') :marked - This time we pass the route list to the `forChild` method of the `RouterModule`. - It's only responsible for providing additional routes and is intended for feature modules. + This time you pass the route list to the `forChild` method of the `RouterModule`. + The route list is only responsible for providing additional routes and is intended for feature modules. .alert.is-important :marked - Always call `RouterModule.forChild` in a feature routing module. + Always call `RouterModule.forChild` in a feature-routing module. .alert.is-helpful :marked - **_forRoot_** and **_forChild_** are conventional names for methods that + _forRoot_ and _forChild_ are conventional names for methods that deliver different `import` values to root and feature modules. Angular doesn't recognize them but Angular developers do. [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. + that has both shared [declarables](../cookbook/ngmodule-faq.html#q-declarable) and services. :marked - `ContactModule` has changed in two small but important details + `ContactModule` has changed in two small but important ways. +makeTabs( `ngmodule/ts/src/app/contact/contact.module.3.ts, ngmodule/ts/src/app/contact/contact.module.2.ts`, @@ -744,23 +753,23 @@ a#lazy-load `src/app/contact/contact.module.3.ts, src/app/contact/contact.module.2.ts`) :marked - 1. It imports the `ContactRoutingModule` object from `contact-routing.module.ts` - 1. It no longer exports `ContactComponent` + * It imports the `ContactRoutingModule` object from `contact-routing.module.ts`. + * It no longer exports `ContactComponent`. - Now that we navigate to `ContactComponent` with the router there's no reason to make it public. - Nor does it need a selector. + Now that you navigate to `ContactComponent` with the router, there's no reason to make it public. + Also, `ContactComponent` doesn't need a selector. No template will ever again reference this `ContactComponent`. - It's gone from the [_AppComponent_ template](#app-component-template). + It's gone from the [AppComponent template](#app-component-template). a#hero-module :marked - ### Lazy loaded routing to a module + ### Lazy-loaded routing to a module - The lazy loaded `HeroModule` and `CrisisModule` follow the same principles as any feature module. + The lazy-loaded `HeroModule` and `CrisisModule` follow the same principles as any feature module. They don't look different from the eagerly loaded `ContactModule`. - The `HeroModule` is a bit more complex than the `CrisisModule` which makes it - a more interesting and useful example. Here's its file structure: + The `HeroModule` is a bit more complex than the `CrisisModule`, which makes it + a more interesting and useful example. Its file structure is as follows: .filetree .file hero @@ -773,15 +782,16 @@ a#hero-module .file hero.service.ts .file highlight.directive.ts :marked - This is the child routing scenario familiar to readers of the [Router](router.html#child-routing-component) page. + This is the child routing scenario familiar to readers of the + [Child routing component](router.html#child-routing-component) section of the + [Routing & Navigation](router.html#child-routing-component) page. The `HeroComponent` is the feature's top component and routing host. Its template has a `` that displays either a list of heroes (`HeroList`) or an editor of a selected hero (`HeroDetail`). Both components delegate to the `HeroService` to fetch and save data. - There's yet _another_ `HighlightDirective` that colors elements in yet a different shade. - We should [do something](#shared-module "Shared modules") about the repetition and inconsistencies. - We endure for now. + Yet another `HighlightDirective` colors elements in yet a different shade. + In the next section, [Shared modules](#shared-module "Shared modules"), you'll resolve the repetition and inconsistencies. The `HeroModule` is a feature module like any other. +makeExample('ngmodule/ts/src/app/hero/hero.module.3.ts', 'class', 'src/app/hero/hero.module.ts (class)')(format='.') @@ -789,7 +799,7 @@ a#hero-module It imports the `FormsModule` because the `HeroDetailComponent` template binds with `[(ngModel)]`. It imports the `HeroRoutingModule` from `hero-routing.module.ts` just as `ContactModule` and `CrisisModule` do. - The `CrisisModule` is much the same. There's nothing more to say that's new. + The `CrisisModule` is much the same. Try the live example. @@ -799,35 +809,35 @@ a#shared-module ## Shared modules The app is shaping up. - One thing we don't like is carrying three different versions of the `HighlightDirective`. - And there's a bunch of other stuff cluttering the app folder level that could be tucked away. + But it carries three different versions of the `HighlightDirective`. + And the many files cluttering the app folder level could be better organized. - Let's add a `SharedModule` to hold the common components, directives, and pipes + Add a `SharedModule` to hold the common components, directives, and pipes and share them with the modules that need them. - * create an `src/app/shared` folder - * move the `AwesomePipe` and `HighlightDirective` from `src/app/contact` to `src/app/shared`. - * delete the `HighlightDirective` classes from `src/app/` and `src/app/hero` - * create a `SharedModule` class to own the shared material - * update other feature modules to import `SharedModule` + 1. Create an `src/app/shared` folder. + * Move the `AwesomePipe` and `HighlightDirective` from `src/app/contact` to `src/app/shared`. + * Delete the `HighlightDirective` classes from `src/app/` and `src/app/hero`. + * Create a `SharedModule` class to own the shared material. + * Update other feature modules to import `SharedModule`. - Most of this is familiar blocking and tackling. Here is the `SharedModule` + Here is the `SharedModule`: +makeExample('ngmodule/ts/src/app/shared/shared.module.ts', '', 'src/app/src/app/shared/shared.module.ts') :marked - Some highlights + Note the following: * It imports the `CommonModule` because its component needs common directives. * It declares and exports the utility pipe, directive, and component classes as expected. * It re-exports the `CommonModule` and `FormsModule` ### Re-exporting other modules - While reviewing our application, we noticed that many components requiring `SharedModule` directives + If you review the application, you may notice that many components requiring `SharedModule` directives also use `NgIf` and `NgFor` from `CommonModule` and bind to component properties with `[(ngModel)]`, a directive in the `FormsModule`. - Modules that declare these components would have to import `CommonModule`, `FormsModule` and `SharedModule`. + Modules that declare these components would have to import `CommonModule`, `FormsModule`, and `SharedModule`. - We can reduce the repetition by having `SharedModule` re-export `CommonModule` and `FormsModule` - so that importers of `SharedModule` get `CommonModule` and `FormsModule` _for free_. + You can reduce the repetition by having `SharedModule` re-export `CommonModule` and `FormsModule` + so that importers of `SharedModule` get `CommonModule` and `FormsModule` for free. As it happens, the components declared by `SharedModule` itself don't bind with `[(ngModel)]`. Technically, there is no need for `SharedModule` to import `FormsModule`. @@ -836,63 +846,65 @@ a#shared-module ### Why _TitleComponent_ isn't shared - `SharedModule` exists to make commonly used components, directives and pipes available - for use in the templates of components in _many_ other modules. + `SharedModule` exists to make commonly used components, directives, and pipes available + for use in the templates of components in many other modules. - The `TitleComponent` is used _only once_ by the `AppComponent`. + The `TitleComponent` is used only once by the `AppComponent`. There's no point in sharing it. ### Why _UserService_ isn't shared - While many components share the same service _instances_, + While many components share the same service instances, they rely on Angular dependency injection to do this kind of sharing, not the module system. - Several components of our sample inject the `UserService`. - There should be _only one_ instance of the `UserService` in the entire application - and _only one_ provider of it. + Several components of the sample inject the `UserService`. + There should be only one instance of the `UserService` in the entire application + and only one provider of it. `UserService` is an application-wide singleton. - We don't want each module to have its own separate instance. + You don't want each module to have its own separate instance. 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 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. + Do *not* specify app-wide singleton `providers` in a shared module. + A lazy-loaded module that imports that shared module makes its own copy of the service. a#core-module .l-main-section :marked ## The Core module - At the moment, our root folder is cluttered with the `UserService` - and the `TitleComponent` that only appears in the root `AppComponent`. - We did not include them in the `SharedModule` for reasons just explained. + At the moment, the root folder is cluttered with the `UserService` + and `TitleComponent` that only appear in the root `AppComponent`. + You didn't include them in the `SharedModule` for reasons just explained. - Instead, we'll gather them in a single `CoreModule` that we **import _once_ when the app starts** - and _never import anywhere else_. + Instead, gather them in a single `CoreModule` that you import once when the app starts + and never import anywhere else. + + Perform the following steps: - **Steps:** + 1. Create an `src/app/core` folder. + * Move the `UserService` and `TitleComponent` from `src/app/` to `src/app/core`. + * Create a `CoreModule` class to own the core material. + * Update the `AppRoot` module to import `CoreModule`. - * create an `src/app/core` folder - * move the `UserService` and `TitleComponent` from `src/app/` to `src/app/core` - * create a `CoreModule` class to own the core material - * update the `AppRoot` module to import `CoreModule` - - Again, most of this is familiar blocking and tackling. The interesting part is the `CoreModule` + Most of this work is familiar. The interesting part is the `CoreModule`. +makeExample('ngmodule/ts/src/app/core/core.module.ts', 'v4', 'src/app/src/app/core/core.module.ts') .l-sub-section :marked - We're importing some extra symbols from the Angular core library that we're not using yet. + You're importing some extra symbols from the Angular core library that you're not using yet. They'll become relevant later in this page. :marked The `@NgModule` metadata should be familiar. - We declare the `TitleComponent` because this module _owns_ it and we export it + You declare the `TitleComponent` because this module owns it and you export it because `AppComponent` (which is in `AppModule`) displays the title in its template. - `TitleComponent` needs the Angular `NgIf` directive that we import from `CommonModule`. + `TitleComponent` needs the Angular `NgIf` directive that you import from `CommonModule`. - `CoreModule` _provides_ the `UserService`. Angular registers that provider with the app root injector, + `CoreModule` provides the `UserService`. Angular registers that provider with the app root injector, making a singleton instance of the `UserService` available to any component that needs it, whether that component is eagerly or lazily loaded. @@ -904,29 +916,29 @@ a#core-module A `TitleComponent` sitting in the root folder isn't bothering anyone. The root `AppModule` can register the `UserService` itself, - as it does currently, even if we decide to relocate the `UserService` file to the `src/app/core` folder. + as it does currently, even if you decide to relocate the `UserService` file to the `src/app/core` folder. - Real world apps have more to worry about. - They can have several single-use components (e.g., spinners, message toasts, and modal dialogs) + Real-world apps have more to worry about. + They can have several single-use components (such as spinners, message toasts, and modal dialogs) that appear only in the `AppComponent` template. - We don't import them elsewhere so they're not _shared_ in that sense. + You don't import them elsewhere so they're not shared in that sense. Yet they're too big and messy to leave loose in the root folder. Apps often have many singleton services like this sample's `UserService`. - Each must be registered _exactly once_, in the app root injector, when the application starts. + Each must be registered exactly once, in the app root injector, when the application starts. - While many Components inject such services in their constructors — - and therefore require JavaScript `import` statements to import their symbols — - no other component or module should define or re-create the services themselves. - Their _providers_ are not shared. + While many components inject such services in their constructors—and + therefore require JavaScript `import` statements to import their symbols—no + other component or module should define or re-create the services themselves. + Their _providers_ aren't shared. - We recommend collecting such single-use classes and hiding their gory details inside a `CoreModule`. + We recommend collecting such single-use classes and hiding their details inside a `CoreModule`. A simplified root `AppModule` imports `CoreModule` in its capacity as orchestrator of the application as a whole. .l-main-section :marked ## Cleanup - Having refactored to a `CoreModule` and a `SharedModule`, it's time to cleanup the other modules. + Having refactored to a `CoreModule` and a `SharedModule`, it's time to clean up the other modules. ### A trimmer _AppModule_ @@ -939,11 +951,11 @@ a#core-module src/app/app.module.ts (v3)`) :marked - Notice that `AppModule` is ... - * a little smaller because many `src/app/root` classes have moved to other modules. - * stable because we'll add future components and providers to other modules, not this one. - * delegating to imported modules rather than doing work. - * focused on its main task, orchestrating the app as a whole. + `AppModule` now has the following qualities: + * A little smaller because many `src/app/root` classes have moved to other modules. + * Stable because you'll add future components and providers to other modules, not this one. + * Delegated to imported modules rather than doing work. + * Focused on its main task, orchestrating the app as a whole. ### A trimmer _ContactModule_ Here is the new `ContactModule` paired with the prior version: @@ -955,10 +967,10 @@ a#core-module src/app/contact/contact.module.ts (v3)`) :marked - Notice that + Notice the following: * The `AwesomePipe` and `HighlightDirective` are gone. - * The imports include `SharedModule` instead of `CommonModule` and `FormsModule` - * This new version is leaner and cleaner. + * The imports include `SharedModule` instead of `CommonModule` and `FormsModule`. + * The new version is leaner and cleaner. .l-hr @@ -969,30 +981,30 @@ a#core-for-root A module that adds providers to the application can offer a facility for configuring those providers as well. - By convention, the **_forRoot_** static method both provides and configures services at the same time. + By convention, the `forRoot` static method both provides and configures services at the same time. It takes a service configuration object and returns a - [ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html) which is - a simple object with two properties: - * `ngModule` - the `CoreModule` class - * `providers` - the configured providers + [ModuleWithProviders](../api/core/index/ModuleWithProviders-interface.html), which is + a simple object with the following properties: + * `ngModule`: the `CoreModule` class + * `providers`: the configured providers The root `AppModule` imports the `CoreModule` and adds the `providers` to the `AppModule` providers. .l-sub-section :marked - More precisely, Angular accumulates all imported providers _before_ appending the items listed in `@NgModule.providers`. - This sequence ensures that whatever we add explicitly to the `AppModule` providers takes precedence + More precisely, Angular accumulates all imported providers before appending the items listed in `@NgModule.providers`. + This sequence ensures that whatever you add explicitly to the `AppModule` providers takes precedence over the providers of imported modules. :marked - Let's add a `CoreModule.forRoot` method that configures the core `UserService`. + Add a `CoreModule.forRoot` method that configures the core `UserService`. - We've extended the core `UserService` with an optional, injected `UserServiceConfig`. + You've extended the core `UserService` with an optional, injected `UserServiceConfig`. If a `UserServiceConfig` exists, the `UserService` sets the user name from that config. +makeExample('ngmodule/ts/src/app/core/user.service.ts', 'ctor', 'src/app/core/user.service.ts (constructor)')(format='.') :marked Here's `CoreModule.forRoot` that takes a `UserServiceConfig` object: +makeExample('ngmodule/ts/src/app/core/core.module.ts', 'for-root', 'src/app/core/core.module.ts (forRoot)')(format='.') :marked - Lastly, we call it _within the_ `imports` _list_ of the `AppModule`. + Lastly, call it within the `imports` list of the `AppModule`. +makeExample('ngmodule/ts/src/app/app.module.ts', 'import-for-root', 'src/app//app.module.ts (imports)')(format='.') :marked The app displays "Miss Marple" as the user instead of the default "Sherlock Holmes". @@ -1000,8 +1012,8 @@ a#core-for-root .alert.is-important :marked Call `forRoot` only in the root application module, `AppModule`. - Calling it in any other module, particularly in a lazy loaded module, - is contrary to the intent and is likely to produce a runtime error. + Calling it in any other module, particularly in a lazy-loaded module, + is contrary to the intent and can produce a runtime error. Remember to _import_ the result; don't add it to any other `@NgModule` list. @@ -1013,31 +1025,33 @@ a#prevent-reimport ## Prevent reimport of the _CoreModule_ Only the root `AppModule` should import the `CoreModule`. - [Bad things happen](../cookbook/ngmodule-faq.html#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. + You could hope that no developer makes that mistake. + Or you can guard against it and fail fast by adding the following `CoreModule` constructor. +makeExample('ngmodule/ts/src/app/core/core.module.ts', 'ctor')(format='.') :marked The constructor tells Angular to inject the `CoreModule` into itself. That seems dangerously circular. - The injection _would be circular_ if Angular looked for `CoreModule` in the _current_ injector. - The `@SkipSelf` decorator means "_look for_ `CoreModule` _in an ancestor injector, above me in the injector hierarchy._" + The injection would be circular if Angular looked for `CoreModule` in the _current_ injector. + The `@SkipSelf` decorator means "look for `CoreModule` in an ancestor injector, above me in the injector hierarchy." If the constructor executes as intended in the `AppModule`, there is no ancestor injector that could provide an instance of `CoreModule`. The injector should give up. - By default the injector throws an error when it can't find a requested provider. + By default, the injector throws an error when it can't find a requested provider. The `@Optional` decorator means not finding the service is OK. The injector returns `null`, the `parentModule` parameter is null, and the constructor concludes uneventfully. - It's a different story if we improperly import `CoreModule` into a lazy loaded module such as `HeroModule` (try it). + It's a different story if you improperly import `CoreModule` into a lazy-loaded module such as `HeroModule` (try it). - Angular creates a lazy loaded module with its own injector, a _child_ of the root injector. - `@SkipSelf` causes Angular to look for a `CoreModule` in the parent injector which this time is the root injector. + Angular creates a lazy-loaded module with its own injector, a _child_ of the root injector. + `@SkipSelf` causes Angular to look for a `CoreModule` in the parent injector, which this time is the root injector. Of course it finds the instance imported by the root `AppModule`. Now `parentModule` exists and the constructor throws the error. :marked @@ -1046,8 +1060,8 @@ a#prevent-reimport You made it! You can examine and download the complete source for this final version from the live example. - ### Frequently Asked Questions + ### Frequently asked questions - Now that you understand Angular Modules, you may be interested - in the companion [Angular Module FAQs](../cookbook/ngmodule-faq.html "Angular Module FAQs") cookbook + Now that you understand NgModules, you may be interested + in the companion [NgModule FAQs](../cookbook/ngmodule-faq.html "NgModule FAQs") page with its ready answers to specific design and implementation questions. diff --git a/public/docs/ts/latest/guide/pipes.jade b/public/docs/ts/latest/guide/pipes.jade index 17766b76a9..dc4acbdcd5 100644 --- a/public/docs/ts/latest/guide/pipes.jade +++ b/public/docs/ts/latest/guide/pipes.jade @@ -124,7 +124,7 @@ figure.image-display +makeExample('pipes/ts/src/app/app.component.html', 'chained-parameter-birthday')(format=".") -.l-main-section +.l-main-section#custom-pipes :marked ## Custom pipes diff --git a/public/docs/ts/latest/index.jade b/public/docs/ts/latest/index.jade index 181bd0ce31..763b4f3cbc 100644 --- a/public/docs/ts/latest/index.jade +++ b/public/docs/ts/latest/index.jade @@ -23,8 +23,6 @@ .c4.secondary-content-list h4 Advanced Documentation ul - li - a(href="/docs/#{lang}/#{vers}/guide/ngmodule.html") Angular Modules li a(href="/docs/#{lang}/#{vers}/guide/animations.html") Animations li @@ -34,7 +32,9 @@ li a(href="/docs/#{lang}/#{vers}/guide/component-styles.html") Component Styles li - a(href="/docs/#{lang}/#{vers}/guide/ngmodule.html") View All... + a(href="/docs/#{lang}/#{vers}/guide/deployment.html") Deployment + li + a(href="/docs/#{lang}/#{vers}/guide/animations.html") View All... .c4.secondary-content-list h4 Cookbook @@ -43,12 +43,12 @@ a(href="/docs/#{lang}/#{vers}/cookbook/aot-compiler.html") Ahead-of-time Compilation li a(href="/docs/#{lang}/#{vers}/cookbook/ajs-quick-reference.html") AngularJS to Angular - li - a(href="/docs/#{lang}/#{vers}/cookbook/ngmodule-faq.html") Angular Module FAQ li a(href="/docs/#{lang}/#{vers}/cookbook/component-communication.html") Component Interaction li a(href="/docs/#{lang}/#{vers}/cookbook/component-relative-paths.html") Component-Relative Paths + li + a(href="/docs/#{lang}/#{vers}/cookbook/dependency-injection.html") Dependency Injection li a(href="/docs/#{lang}/#{vers}/cookbook/") View All...