From 3e34ba01bdbeea237cb7c50e9cea3b0ed3b0606b Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 22 Feb 2017 18:09:39 +0000 Subject: [PATCH] docs(aio): migrate content docs from angular.io This content was generated by a tool: https://github.com/petebacondarwin/aio-migrator --- aio/content/cookbook/ajs-quick-reference.md | 1174 ++++++ aio/content/cookbook/aot-compiler.md | 623 +++ .../cookbook/component-communication.md | 301 ++ .../cookbook/component-relative-paths.md | 100 +- aio/content/cookbook/dependency-injection.md | 921 +++++ .../cookbook/dynamic-component-loader.md | 138 + aio/content/cookbook/dynamic-form.md | 168 + aio/content/cookbook/form-validation.md | 486 +++ aio/content/cookbook/i18n.md | 620 +++ aio/content/cookbook/index.md | 28 + aio/content/cookbook/set-document-title.md | 103 + aio/content/cookbook/ts-to-js.md | 868 ++++ aio/content/cookbook/visual-studio-2015.md | 171 + aio/content/guide/animations.md | 370 ++ aio/content/guide/appmodule.md | 157 + aio/content/guide/architecture.md | 401 ++ aio/content/guide/attribute-directives.md | 396 ++ aio/content/guide/browser-support.md | 614 +++ aio/content/guide/change-log.md | 187 + aio/content/guide/cheatsheet.md | 3 + aio/content/guide/component-styles.md | 291 ++ aio/content/guide/dependency-injection.md | 737 ++++ aio/content/guide/deployment.md | 549 +++ aio/content/guide/displaying-data.md | 186 + aio/content/guide/forms.md | 736 ++++ aio/content/guide/glossary.md | 6 + .../hierarchical-dependency-injection.md | 184 + aio/content/guide/index.md | 152 + aio/content/guide/learning-angular.md | 46 + aio/content/guide/lifecycle-hooks.md | 679 +++ aio/content/guide/ngcontainer.md | 12 + aio/content/guide/ngmodule.md | 1216 ++++++ aio/content/guide/npm-packages.md | 206 + aio/content/guide/reactive-forms.md | 1159 ++++++ aio/content/guide/router.md | 2838 +++++++++++++ aio/content/guide/security.md | 142 + aio/content/guide/server-communication.md | 390 ++ aio/content/guide/setup.md | 223 + aio/content/guide/structural-directives.md | 614 +++ aio/content/guide/style-guide.md | 3649 +++++++++++++++++ aio/content/guide/template-syntax.md | 1899 +++++++++ aio/content/guide/upgrade.md | 2191 ++++++++++ aio/content/guide/user-input.md | 256 ++ aio/content/guide/webpack.md | 572 +++ aio/content/tutorial/index.md | 82 + aio/content/tutorial/toh-pt1.md | 229 ++ aio/content/tutorial/toh-pt2.md | 356 ++ aio/content/tutorial/toh-pt3.md | 365 ++ aio/content/tutorial/toh-pt4.md | 473 +++ aio/content/tutorial/toh-pt5.md | 510 +++ aio/content/tutorial/toh-pt6.md | 293 ++ 51 files changed, 29037 insertions(+), 33 deletions(-) create mode 100644 aio/content/cookbook/ajs-quick-reference.md create mode 100644 aio/content/cookbook/aot-compiler.md create mode 100644 aio/content/cookbook/component-communication.md create mode 100644 aio/content/cookbook/dependency-injection.md create mode 100644 aio/content/cookbook/dynamic-component-loader.md create mode 100644 aio/content/cookbook/dynamic-form.md create mode 100644 aio/content/cookbook/form-validation.md create mode 100644 aio/content/cookbook/i18n.md create mode 100644 aio/content/cookbook/index.md create mode 100644 aio/content/cookbook/set-document-title.md create mode 100644 aio/content/cookbook/ts-to-js.md create mode 100644 aio/content/cookbook/visual-studio-2015.md create mode 100644 aio/content/guide/animations.md create mode 100644 aio/content/guide/appmodule.md create mode 100644 aio/content/guide/architecture.md create mode 100644 aio/content/guide/attribute-directives.md create mode 100644 aio/content/guide/browser-support.md create mode 100644 aio/content/guide/change-log.md create mode 100644 aio/content/guide/cheatsheet.md create mode 100644 aio/content/guide/component-styles.md create mode 100644 aio/content/guide/dependency-injection.md create mode 100644 aio/content/guide/deployment.md create mode 100644 aio/content/guide/displaying-data.md create mode 100644 aio/content/guide/forms.md create mode 100644 aio/content/guide/glossary.md create mode 100644 aio/content/guide/hierarchical-dependency-injection.md create mode 100644 aio/content/guide/index.md create mode 100644 aio/content/guide/learning-angular.md create mode 100644 aio/content/guide/lifecycle-hooks.md create mode 100644 aio/content/guide/ngcontainer.md create mode 100644 aio/content/guide/ngmodule.md create mode 100644 aio/content/guide/npm-packages.md create mode 100644 aio/content/guide/reactive-forms.md create mode 100644 aio/content/guide/router.md create mode 100644 aio/content/guide/security.md create mode 100644 aio/content/guide/server-communication.md create mode 100644 aio/content/guide/setup.md create mode 100644 aio/content/guide/structural-directives.md create mode 100644 aio/content/guide/style-guide.md create mode 100644 aio/content/guide/template-syntax.md create mode 100644 aio/content/guide/upgrade.md create mode 100644 aio/content/guide/user-input.md create mode 100644 aio/content/guide/webpack.md create mode 100644 aio/content/tutorial/index.md create mode 100644 aio/content/tutorial/toh-pt1.md create mode 100644 aio/content/tutorial/toh-pt2.md create mode 100644 aio/content/tutorial/toh-pt3.md create mode 100644 aio/content/tutorial/toh-pt4.md create mode 100644 aio/content/tutorial/toh-pt5.md create mode 100644 aio/content/tutorial/toh-pt6.md diff --git a/aio/content/cookbook/ajs-quick-reference.md b/aio/content/cookbook/ajs-quick-reference.md new file mode 100644 index 0000000000..dcada58916 --- /dev/null +++ b/aio/content/cookbook/ajs-quick-reference.md @@ -0,0 +1,1174 @@ +@title +AngularJS to Angular Quick Reference + +@intro +Learn how AngularJS concepts and techniques map to Angular + +@description + + +{@a top} +_Angular_ is the name for the Angular of today and tomorrow. +_AngularJS_ is the name for all v1.x versions of Angular. + +This guide helps you transition from AngularJS to Angular +by mapping AngularJS syntax to the equivalent Angular syntax. +**See the Angular syntax in this **. + +## Contents +This page covers: +* [Template basics](#template-basics) - binding and local variables. + +* [Template directives](#template-directives) - built-in directives `ngIf` and `ngClass`. + +* [Filters/pipes](#filters-pipes) - built-in *filters*, known as *pipes* in Angular. + +* [Modules/controllers/components](#controllers-components) - *modules* in Angular are slightly different from *modules* in AngularJS, and *controllers* are *components* in Angular. + +* [Style sheets](#style-sheets) - more options for CSS than in AngularJS. + +## Template basics +Templates are the user-facing part of an Angular application and are written in HTML. +The following table lists some of the key AngularJS template features with their equivalent Angular template syntax. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AngularJS + + Angular +
+ ### Bindings/interpolation + + Your favorite hero is: {{vm.favoriteHero}} + + + In AngularJS, an expression in curly braces denotes one-way binding. + This binds the value of the element to a property in the controller + associated with this template. + + When using the `controller as` syntax, + the binding is prefixed with the controller alias (`vm` or `$ctrl`) because you + have to be specific about the source of the binding. + + ### Bindings/interpolation + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='interpolation'} + + In Angular, a template expression in curly braces still denotes one-way binding. + This binds the value of the element to a property of the component. + The context of the binding is implied and is always the + associated component, so it needs no reference variable. + + For more information, see the [Interpolation](../guide/template-syntax.html#interpolation) section of the Template Syntax page. +
+ ### Filters + + <td>{{movie.title | uppercase}}</td> + + + To filter output in AngularJS templates, use the pipe character (|) and one or more filters. + + This example filters the `title` property to uppercase. + + ### Pipes + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='uppercase'} + + In Angular you use similar syntax with the pipe (|) character to filter output, but now you call them **pipes**. + Many (but not all) of the built-in filters from AngularJS are + built-in pipes in Angular. + + For more information, see the heading [Filters/pipes](#filters-pipes) below. +
+ ### Local variables + + <tr ng-repeat="movie in vm.movies"> + <td>{{movie.title}}</td> + </tr> + + + Here, `movie` is a user-defined local variable. + + ### Input variables + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='local'} + + Angular has true template input variables that are explicitly defined using the `let` keyword. + + For more information, see the [ngFor micro-syntax](../guide/template-syntax.html#ngForMicrosyntax) section of the Template Syntax page. +
+ +[Back to top](#top) + +## Template directives +AngularJS provides more than seventy built-in directives for templates. +Many of them aren't needed in Angular because of its more capable and expressive binding system. +The following are some of the key AngularJS built-in directives and their equivalents in Angular. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AngularJS + + Angular +
+ ### ng-app + + <body ng-app="movieHunter"> + + + The application startup process is called **bootstrapping**. + + Although you can bootstrap an AngularJS app in code, + many applications bootstrap declaratively with the `ng-app` directive, + giving it the name of the application's module (`movieHunter`). + + ### Bootstrapping + + {@example 'cb-ajs-quick-reference/ts/src/main.ts'} + +
+ + {@example 'cb-ajs-quick-reference/ts/src/app/app.module.1.ts'} + + Angular doesn't have a bootstrap directive. + To launch the app in code, explicitly bootstrap the application's root module (`AppModule`) + in `main.ts` + and the application's root component (`AppComponent`) in `app.module.ts`. + + For more information see the [Setup](../guide/setup.html) page. +
+ ### ng-class + + <div ng-class="{active: isActive}"> + <div ng-class="{active: isActive, + shazam: isImportant}"> + + + In AngularJS, the `ng-class` directive includes/excludes CSS classes + based on an expression. That expression is often a key-value control object with each + key of the object defined as a CSS class name, and each value defined as a template expression + that evaluates to a Boolean value. + + In the first example, the `active` class is applied to the element if `isActive` is true. + + You can specify multiple classes, as shown in the second example. + + ### ngClass + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='ngClass'} + + In Angular, the `ngClass` directive works similarly. + It includes/excludes CSS classes based on an expression. + + In the first example, the `active` class is applied to the element if `isActive` is true. + + You can specify multiple classes, as shown in the second example. + + Angular also has **class binding**, which is a good way to add or remove a single class, + as shown in the third example. + + For more information see the [Attribute, Class, and Style Bindings](../guide/template-syntax.html#other-bindings) section of the Template Syntax page. + +
+ ### ng-click + + <button ng-click="vm.toggleImage()"> + <button ng-click="vm.toggleImage($event)"> + + + In AngularJS, the `ng-click` directive allows you to specify custom behavior when an element is clicked. + + In the first example, when the user clicks the button, the `toggleImage()` method in the controller referenced by the `vm` `controller as` alias is executed. + + The second example demonstrates passing in the `$event` object, which provides details about the event + to the controller. + + ### bind to the `click` event + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='event-binding'} + + AngularJS event-based directives do not exist in Angular. + Rather, define one-way binding from the template view to the component using **event binding**. + + For event binding, define the name of the target event within parenthesis and + specify a template statement, in quotes, to the right of the equals. Angular then + sets up an event handler for the target event. When the event is raised, the handler + executes the template statement. + + In the first example, when a user clicks the button, the `toggleImage()` method in the associated component is executed. + + The second example demonstrates passing in the `$event` object, which provides details about the event + to the component. + + For a list of DOM events, see: https://developer.mozilla.org/en-US/docs/Web/Events. + + For more information, see the [Event Binding](../guide/template-syntax.html#event-binding) section of the Template Syntax page. + +
+ ### ng-controller + + <div ng-controller="MovieListCtrl as vm"> + + + In AngularJS, the `ng-controller` directive attaches a controller to the view. + Using the `ng-controller` (or defining the controller as part of the routing) ties the + view to the controller code associated with that view. + + ### Component decorator + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='component'} + + In Angular, the template no longer specifies its associated controller. + Rather, the component specifies its associated template as part of the component class decorator. + + For more information, see [Architecture Overview](../guide/architecture.html#component). + +
+ ### ng-hide + In AngularJS, the `ng-hide` directive shows or hides the associated HTML element based on + an expression. For more information, see [ng-show](#ng-show). + + ### bind to the `hidden` property + In Angular, you use property binding; there is no built-in *hide* directive. + For more information, see [ng-show](#ng-show). +
+ ### ng-href + + <a ng-href="angularDocsUrl">Angular Docs</a> + + + The `ng-href` directive allows AngularJS to preprocess the `href` property so that it + can replace the binding expression with the appropriate URL before the browser + fetches from that URL. + + In AngularJS, the `ng-href` is often used to activate a route as part of navigation. + + <a ng-href="#movies">Movies</a> + + + Routing is handled differently in Angular. + + ### bind to the `href` property + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='href'} + + Angular, uses property binding; there is no built-in *href* directive. + Place the element's `href` property in square brackets and set it to a quoted template expression. + + For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding). + + In Angular, `href` is no longer used for routing. Routing uses `routerLink`, as shown in the third example. + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='router-link'} + + For more information on routing, see [Routing & Navigation](../guide/router.html#router-link). + +
+ ### ng-if + + <table ng-if="movies.length"> + + + In AngularJS, the `ng-if` directive removes or recreates a portion of the DOM, + based on an expression. If the expression is false, the element is removed from the DOM. + + In this example, the `table` element is removed from the DOM unless the `movies` array has a length greater than zero. + + ### *ngIf + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngIf'} + + The `*ngIf` directive in Angular works the same as the `ng-if` directive in AngularJS. It removes or recreates a portion of the DOM based on an expression. + + In this example, the `table` element is removed from the DOM unless the `movies` array has a length. + + The (*) before `ngIf` is required in this example. + For more information, see [Structural Directives](../guide/structural-directives.html). +
+ ### ng-model + + <input ng-model="vm.favoriteHero"/> + + + In AngularJS, the `ng-model` directive binds a form control to a property in the controller associated with the template. + This provides **two-way binding**, whereby any change made to the value in the view is synchronized with the model, and any change to the model is synchronized with the value in the view. + + ### ngModel + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngModel'} + + In Angular, **two-way binding** is denoted by `[()]`, descriptively referred to as a "banana in a box". This syntax is a shortcut for defining both property binding (from the component to the view) + and event binding (from the view to the component), thereby providing two-way binding. + + For more information on two-way binding with ngModel, see [Template Syntax](../guide/template-syntax.html#ngModel). +
+ ### ng-repeat + + <tr ng-repeat="movie in vm.movies"> + + + In AngularJS, the `ng-repeat` directive repeats the associated DOM element + for each item in the specified collection. + + In this example, the table row (`tr`) element repeats for each movie object in the collection of movies. + + ### *ngFor + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngFor'} + + The `*ngFor` directive in Angular is similar to the `ng-repeat` directive in AngularJS. It repeats the associated DOM element for each item in the specified collection. + More accurately, it turns the defined element (`tr` in this example) and its contents into a template and + uses that template to instantiate a view for each item in the list. + + Notice the other syntax differences: + The (*) before `ngFor` is required; + the `let` keyword identifies `movie` as an input variable; + the list preposition is `of`, not `in`. + + For more information, see [Structural Directives](../guide/structural-directives.html). +
+ ### ng-show + + <h3 ng-show="vm.favoriteHero"> + Your favorite hero is: {{vm.favoriteHero}} + </h3> + + + In AngularJS, the `ng-show` directive shows or hides the associated DOM element, based on + an expression. + + In this example, the `div` element is shown if the `favoriteHero` variable is truthy. + + ### bind to the `hidden` property + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='hidden'} + + Angular, uses property binding; there is no built-in *show* directive. + For hiding and showing elements, bind to the HTML `hidden` property. + + To conditionally display an element, place the element's `hidden` property in square brackets and + set it to a quoted template expression that evaluates to the *opposite* of *show*. + + In this example, the `div` element is hidden if the `favoriteHero` variable is not truthy. + + For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding). +
+ ### ng-src + + <img ng-src="{{movie.imageurl}}"> + + + The `ng-src` directive allows AngularJS to preprocess the `src` property so that it + can replace the binding expression with the appropriate URL before the browser + fetches from that URL. + + ### bind to the `src` property + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='src'} + + Angular, uses property binding; there is no built-in *src* directive. + Place the `src` property in square brackets and set it to a quoted template expression. + + For more information on property binding, see [Template Syntax](../guide/template-syntax.html#property-binding). +
+ ### ng-style + + <div ng-style="{color: colorPreference}"> + + + In AngularJS, the `ng-style` directive sets a CSS style on an HTML element + based on an expression. That expression is often a key-value control object with each + key of the object defined as a CSS style name, and each value defined as an expression + that evaluates to a value appropriate for the style. + + In the example, the `color` style is set to the current value of the `colorPreference` variable. + + ### ngStyle + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='ngStyle'} + + In Angular, the `ngStyle` directive works similarly. It sets a CSS style on an HTML element based on an expression. + + In the first example, the `color` style is set to the current value of the `colorPreference` variable. + + Angular also has **style binding**, which is good way to set a single style. This is shown in the second example. + + For more information on style binding, see [Template Syntax](../guide/template-syntax.html#style-binding). + + For more information on the ngStyle directive, see [Template Syntax](../guide/template-syntax.html#ngStyle). +
+ ### ng-switch + + <div ng-switch="vm.favoriteHero && + vm.checkMovieHero(vm.favoriteHero)"> + <div ng-switch-when="true"> + Excellent choice! + </div> + <div ng-switch-when="false"> + No movie, sorry! + </div> + <div ng-switch-default> + Please enter your favorite hero. + </div> + </div> + + + In AngularJS, the `ng-switch` directive swaps the contents of + an element by selecting one of the templates based on the current value of an expression. + + In this example, if `favoriteHero` is not set, the template displays "Please enter ...". + If `favoriteHero` is set, it checks the movie hero by calling a controller method. + If that method returns `true`, the template displays "Excellent choice!". + If that methods returns `false`, the template displays "No movie, sorry!". + + ### ngSwitch + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.html' region='ngSwitch'} + + In Angular, the `ngSwitch` directive works similarly. + It displays an element whose `*ngSwitchCase` matches the current `ngSwitch` expression value. + + In this example, if `favoriteHero` is not set, the `ngSwitch` value is `null` + and `*ngSwitchDefault` displays, "Please enter ...". + If `favoriteHero` is set, the app checks the movie hero by calling a component method. + If that method returns `true`, the app selects `*ngSwitchCase="true"` and displays: "Excellent choice!" + If that methods returns `false`, the app selects `*ngSwitchCase="false"` and displays: "No movie, sorry!" + + The (*) before `ngSwitchCase` and `ngSwitchDefault` is required in this example. + + For more information on the ngSwitch directive, see [Template Syntax](../guide/template-syntax.html#ngSwitch). +
+ +[Back to top](#top) + + +{@a filters-pipes} + +## Filters/pipes +Angular **pipes** provide formatting and transformation for data in our template, similar to AngularJS **filters**. +Many of the built-in filters in AngularJS have corresponding pipes in Angular. +For more information on pipes, see [Pipes](../guide/pipes.html). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AngularJS + + Angular +
+ ### currency + + <td>{{movie.price | currency}}</td> + + + Formats a number as a currency. + + ### currency + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='currency'} + + The Angular `currency` pipe is similar although some of the parameters have changed. +
+ ### date + + <td>{{movie.releaseDate | date}}</td> + + + Formats a date to a string based on the requested format. + + ### date + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='date'} + + The Angular `date` pipe is similar. + +
+ ### filter + + <tr ng-repeat="movie in movieList | filter: {title:listFilter}"> + + + Selects a subset of items from the defined collection, based on the filter criteria. + + ### none + For performance reasons, no comparable pipe exists in Angular. Do all your filtering in the component. If you need the same filtering code in several templates, consider building a custom pipe. + +
+ ### json + + <pre>{{movie | json}}</pre> + + + Converts a JavaScript object into a JSON string. This is useful for debugging. + + ### json + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='json'} + + The Angular `json` pipe does the same thing. +
+ ### limitTo + + <tr ng-repeat="movie in movieList | limitTo:2:0"> + + + Selects up to the first parameter (2) number of items from the collection + starting (optionally) at the beginning index (0). + + ### slice + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='slice'} + + The `SlicePipe` does the same thing but the *order of the parameters is reversed*, in keeping + with the JavaScript `Slice` method. + The first parameter is the starting index; the second is the limit. + As in AngularJS, coding this operation within the component instead could improve performance. +
+ ### lowercase + + <div>{{movie.title | lowercase}}</div> + + + Converts the string to lowercase. + + ### lowercase + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='lowercase'} + + The Angular `lowercase` pipe does the same thing. +
+ ### number + + <td>{{movie.starRating | number}}</td> + + + Formats a number as text. + + ### number + + {@example 'cb-ajs-quick-reference/ts/src/app/app.component.html' region='number'} + + The Angular `number` pipe is similar. + It provides more functionality when defining + the decimal places, as shown in the second example above. + + Angular also has a `percent` pipe, which formats a number as a local percentage + as shown in the third example. +
+ ### orderBy + + <tr ng-repeat="movie in movieList | orderBy : 'title'"> + + + Displays the collection in the order specified by the expression. + In this example, the movie title orders the movieList. + + ### none + For performance reasons, no comparable pipe exists in Angular. + Instead, use component code to order or sort results. If you need the same ordering or sorting code in several templates, consider building a custom pipe. + +
+ +[Back to top](#top) + + +{@a controllers-components} + +## Modules/controllers/components +In both AngularJS and Angular, Angular modules help you organize your application into cohesive blocks of functionality. + +In AngularJS, you write the code that provides the model and the methods for the view in a **controller**. +In Angular, you build a **component**. + +Because much AngularJS code is in JavaScript, JavaScript code is shown in the AngularJS column. +The Angular code is shown using TypeScript. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AngularJS + + Angular +
+ ### IIFE + + (function () { + ... + }()); + + + In AngularJS, you often defined an immediately invoked function expression (or IIFE) around your controller code. + This kept your controller code out of the global namespace. + + ### none + You don't need to worry about this in Angular because you use ES 2015 modules + and modules handle the namespacing for you. + + For more information on modules, see [Architecture Overview](../guide/architecture.html#module). +
+ ### Angular modules + + angular.module("movieHunter", ["ngRoute"]); + + + In AngularJS, an Angular module keeps track of controllers, services, and other code. The second argument defines the list of other modules that this module depends upon. + + ### Angular modules + + {@example 'cb-ajs-quick-reference/ts/src/app/app.module.1.ts'} + + Angular modules, defined with the `NgModule` decorator, serve the same purpose: + - `imports`: specifies the list of other modules that this module depends upon + - `declaration`: keeps track of your components, pipes, and directives. + + For more information on modules, see [Angular Modules](../guide/ngmodule.html). +
+ ### Controller registration + + angular + .module("movieHunter") + .controller("MovieListCtrl", + ["movieService", + MovieListCtrl]); + + + AngularJS, has code in each controller that looks up an appropriate Angular module + and registers the controller with that module. + + The first argument is the controller name. The second argument defines the string names of + all dependencies injected into this controller, and a reference to the controller function. + + ### Component Decorator + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='component'} + + Angular, adds a decorator to the component class to provide any required metadata. + The Component decorator declares that the class is a component and provides metadata about + that component such as its selector (or tag) and its template. + + This is how you associate a template with code, which is defined in the component class. + + For more information, see the [Components](../guide/architecture.html#components) section of the Architecture Overview page. +
+ ### Controller function + + function MovieListCtrl(movieService) { + } + + + In AngularJS, you write the code for the model and methods in a controller function. + + ### Component class + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='class'} + + In Angular, you create a component class. + + NOTE: If you are using TypeScript with AngularJS, you must use the `export` keyword to export the component class. + + For more information, see the [Components](../guide/architecture.html#components) section of the Architecture Overview page. +
+ ### Dependency injection + + MovieListCtrl.$inject = ['MovieService']; + function MovieListCtrl(movieService) { + } + + + In AngularJS, you pass in any dependencies as controller function arguments. + This example injects a `MovieService`. + + To guard against minification problems, tell Angular explicitly + that it should inject an instance of the `MovieService` in the first parameter. + + ### Dependency injection + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='di'} + + In Angular, you pass in dependencies as arguments to the component class constructor. + This example injects a `MovieService`. + The first parameter's TypeScript type tells Angular what to inject, even after minification. + + For more information, see the [Dependency Injection](../guide/architecture.html#dependency-injection) section of the Architecture Overview. +
+ +[Back to top](#top) + + +{@a style-sheets} + +## Style sheets +Style sheets give your application a nice look. +In AngularJS, you specify the style sheets for your entire application. +As the application grows over time, the styles for the many parts of the application +merge, which can cause unexpected results. +In Angular, you can still define style sheets for your entire application. But now you can +also encapsulate a style sheet within a specific component. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AngularJS + + Angular +
+ ### Link tag + + <link href="styles.css" rel="stylesheet" /> + + + AngularJS, uses a `link` tag in the head section of the `index.html` file + to define the styles for the application. + + ### Link tag + + {@example 'cb-ajs-quick-reference/ts/src/index.html' region='style'} + + In Angular, you can continue to use the link tag to define the styles for your application in the `index.html` file. + But now you can also encapsulate styles for your components. ### StyleUrls + In Angular, you can use the `styles` or `styleUrls` property of the `@Component` metadata to define + a style sheet for a particular component. + + {@example 'cb-ajs-quick-reference/ts/src/app/movie-list.component.ts' region='style-url'} + + This allows you to set appropriate styles for individual components that won’t leak into + other parts of the application. +
+ +[Back to top](#top) \ No newline at end of file diff --git a/aio/content/cookbook/aot-compiler.md b/aio/content/cookbook/aot-compiler.md new file mode 100644 index 0000000000..7e0c28adc8 --- /dev/null +++ b/aio/content/cookbook/aot-compiler.md @@ -0,0 +1,623 @@ +@title +Ahead-of-Time Compilation + +@intro +Learn how to use Ahead-of-time compilation + +@description +This cookbook describes how to radically improve performance by compiling _Ahead of Time_ (AOT) +during a build process. + + +{@a toc} +## Table of Contents +* [Overview](#overview) +* [_Ahead-of-Time_ vs _Just-in-Time_](#aot-jit) +* [Compile with AOT](#compile) +* [Bootstrap](#bootstrap) +* [Tree Shaking](#tree-shaking) +* [Load the bundle](#load) +* [Serve the app](#serve) +* [Workflow and convenience script](#workflow) +* [Source Code](#source-code) +* [Tour of Heroes](#toh) + + +{@a overview} + +## Overview + +An Angular application consist largely of components and their HTML templates. +Before the browser can render the application, +the components and templates must be converted to executable JavaScript by the _Angular compiler_. +Watch compiler author Tobias Bosch explain the Angular Compiler at AngularConnect 2016.You can compile the app in the browser, at runtime, as the application loads, using the **_Just-in-Time_ (JIT) compiler**. +This is the standard development approach shown throughout the documentation. +It's great .. but it has shortcomings. + +JIT compilation incurs a runtime performance penalty. +Views take longer to render because of the in-browser compilation step. +The application is bigger because it includes the Angular compiler +and a lot of library code that the application won't actually need. +Bigger apps take longer to transmit and are slower to load. + +Compilation can uncover many component-template binding errors. +JIT compilation discovers them at runtime which is later than we'd like. + +The **_Ahead-of-Time_ (AOT) compiler** can catch template errors early and improve performance +by compiling at build time as you'll learn in this chapter. + + + +{@a aot-jit} + +## _Ahead-of-time_ (AOT) vs _Just-in-time_ (JIT) + +There is actually only one Angular compiler. The difference between AOT and JIT is a matter of timing and tooling. +With AOT, the compiler runs once at build time using one set of libraries; +With JIT it runs every time for every user at runtime using a different set of libraries. + +### Why do AOT compilation? + +*Faster rendering* + +With AOT, the browser downloads a pre-compiled version of the application. +The browser loads executable code so it can render the application immediately, without waiting to compile the app first. + +*Fewer asynchronous requests* + +The compiler _inlines_ external html templates and css style sheets within the application JavaScript, +eliminating separate ajax requests for those source files. + +*Smaller Angular framework download size* + +There's no need to download the Angular compiler if the app is already compiled. +The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload. + + +*Detect template errors earlier* + +The AOT compiler detects and reports template binding errors during the build step +before users can see them. + + +*Better security* + +AOT compiles HTML templates and components into JavaScript files long before they are served to the client. +With no templates to read and no risky client-side HTML or JavaScript evaluation, +there are fewer opportunities for injection attacks. + + +{@a compile} + +## Compile with AOT + +### Prepare for offline compilation +Take the Setup as a starting point. +A few minor changes to the lone `app.component` lead to these two class and html files: + + + + + {@example 'cb-aot-compiler/ts/src/app/app.component.html'} + + + + + {@example 'cb-aot-compiler/ts/src/app/app.component.ts'} + + + + + +Install a few new npm dependencies with the following command: + + npm install @angular/compiler-cli @angular/platform-server --save + + +You will run the `ngc` compiler provided in the `@angular/compiler-cli` npm package +instead of the TypeScript compiler (`tsc`). + +`ngc` is a drop-in replacement for `tsc` and is configured much the same way. + +`ngc` requires its own `tsconfig.json` with AOT-oriented settings. +Copy the original `src/tsconfig.json` to a file called `tsconfig-aot.json` (on the project root), +then modify it to look as follows. + + +{@example 'cb-aot-compiler/ts/tsconfig-aot.json'} + +The `compilerOptions` section is unchanged except for one property. +**Set the `module` to `es2015`**. +This is important as explained later in the [Tree Shaking](#tree-shaking) section. + +What's really new is the `ngc` section at the bottom called `angularCompilerOptions`. +Its `"genDir"` property tells the compiler +to store the compiled output files in a new `aot` folder. + +The `"skipMetadataEmit" : true` property prevents the compiler from generating metadata files with the compiled application. +Metadata files are not necessary when targeting TypeScript files, so there is no reason to include them. +***Component-relative Template URLS*** + +The AOT compiler requires that `@Component` URLS for external templates and css files be _component-relative_. +That means that the value of `@Component.templateUrl` is a URL value _relative_ to the component class file. +For example, an `'app.component.html'` URL means that the template file is a sibling of its companion `app.component.ts` file. + +While JIT app URLs are more flexible, stick with _component-relative_ URLs for compatibility with AOT compilation. + +JIT-compiled applications that use the SystemJS loader and _component-relative_ URLs *must set the* `@Component.moduleId` *property to* `module.id`. +The `module` object is undefined when an AOT-compiled app runs. +The app fails with a null reference error unless you assign a global `module` value in the `index.html` like this: + +{@example 'cb-aot-compiler/ts/src/index.html' region='moduleId'} + + +Setting a global `module` is a temporary expedient. +### Compiling the application + +Initiate AOT compilation from the command line using the previously installed `ngc` compiler by executing: + + node_modules/.bin/ngc -p tsconfig-aot.json + + + +Windows users should surround the `ngc` command in double quotes: + + "node_modules/.bin/ngc" -p tsconfig-aot.json + + +`ngc` expects the `-p` switch to point to a `tsconfig.json` file or a folder containing a `tsconfig.json` file. + +After `ngc` completes, look for a collection of _NgFactory_ files in the `aot` folder (the folder specified as `genDir` in `tsconfig-aot.json`). + +These factory files are essential to the compiled application. +Each component factory creates an instance of the component at runtime by combining the original class file +and a JavaScript representation of the component's template. +Note that the original component class is still referenced internally by the generated factory. +The curious can open the `aot/app.component.ngfactory.ts` to see the original Angular template syntax +in its intermediate, compiled-to-TypeScript form. + +JIT compilation generates these same _NgFactories_ in memory where they are largely invisible. +AOT compilation reveals them as separate, physical files. + + +~~~ {.alert.is-important} + +Do not edit the _NgFactories_! Re-compilation replaces these files and all edits will be lost. + + +~~~ + + + +{@a bootstrap} + +## Bootstrap + +The AOT path changes application bootstrapping. + +Instead of bootstrapping `AppModule`, you bootstrap the application with the generated module factory, `AppModuleNgFactory`. + +Make a copy of `main.ts` and name it `main-jit.ts`. +This is the JIT version; set it aside as you may need it [later](#run-jit "Running with JIT"). + +Open `main.ts` and convert it to AOT compilation. +Switch from the `platformBrowserDynamic.bootstrap` used in JIT compilation to +`platformBrowser().bootstrapModuleFactory` and pass in the AOT-generated `AppModuleNgFactory`. + +Here is AOT bootstrap in `main.ts` next to the original JIT version: + + + + + {@example 'cb-aot-compiler/ts/src/main.ts'} + + + + + {@example 'cb-aot-compiler/ts/src/main-jit.ts'} + + + + + +Be sure to recompile with `ngc`! + + +{@a tree-shaking} +## Tree Shaking + +AOT compilation sets the stage for further optimization through a process called _Tree Shaking_. +A Tree Shaker walks the dependency graph, top to bottom, and _shakes out_ unused code like +dead needles in a Christmas tree. + +Tree Shaking can greatly reduce the downloaded size of the application +by removing unused portions of both source and library code. +In fact, most of the reduction in small apps comes from removing unreferenced Angular features. + +For example, this demo application doesn't use anything from the `@angular/forms` library. +There is no reason to download Forms-related Angular code and tree shaking ensures that you don't. + +Tree Shaking and AOT compilation are separate steps. +Tree Shaking can only target JavaScript code. +AOT compilation converts more of the application to JavaScript, +which in turn makes more of the application "Tree Shakable". + +### Rollup + +This cookbook illustrates a Tree Shaking utility called _Rollup_. + +Rollup statically analyzes the application by following the trail of `import` and `export` statements. +It produces a final code _bundle_ that excludes code that is exported, but never imported. + +Rollup can only Tree Shake `ES2015` modules which have `import` and `export` statements. +Recall that `tsconfig-aot.json` is configured to produce `ES2015` modules. +It's not important that the code itself be written with `ES2015` syntax such as `class` and `const`. +What matters is that the code uses ES `import` and `export` statements rather than `require` statements.Install the Rollup dependencies with this command: + + npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev + + +Next, create a configuration file (`rollup-config.js`) +in the project root directory to tell Rollup how to process the application. +The cookbook configuration file looks like this. + + +{@example 'cb-aot-compiler/ts/rollup-config.js'} + +It tells Rollup that the app entry point is `src/app/main.js` . +The `dest` attribute tells Rollup to create a bundle called `build.js` in the `dist` folder. +It overrides the default `onwarn` method in order to skip annoying messages about the AOT compiler's use of the `this` keyword. + +Then there are plugins. +### Rollup Plugins + +Optional plugins filter and transform the Rollup inputs and output. + +*RxJS* +Rollup expects application source code to use `ES2015` modules. +Not all external dependencies are published as `ES2015` modules. +In fact, most are not. Many of them are published as _CommonJS_ modules. + +The _RxJs_ observable library is an essential Angular dependency published as an ES5 JavaScript _CommonJS_ module. + +Luckily there is a Rollup plugin that modifies _RxJs_ +to use the ES `import` and `export` statements that Rollup requires. +Rollup then preserves in the final bundle the parts of `RxJS` referenced by the application. + + +{@example 'cb-aot-compiler/ts/rollup-config.js' region='commonjs'} + +*Minification* + +Rollup Tree Shaking reduces code size considerably. Minification makes it smaller still. +This cookbook relies on the _uglify_ Rollup plugin to minify and mangle the code. + + +{@example 'cb-aot-compiler/ts/rollup-config.js' region='uglify'} + + +In a production setting, you would also enable gzip on the web server to compress +the code into an even smaller package going over the wire. +### Run Rollup +Execute the Rollup process with this command: + + node_modules/.bin/rollup -c rollup-config.js + + + +Windows users should surround the `rollup` command in double quotes: + + "node_modules/.bin/rollup" -c rollup-config.js + + + + +{@a load} + +## Load the Bundle + +Loading the generated application bundle does not require a module loader like SystemJS. +Remove the scripts that concern SystemJS. +Instead, load the bundle file using a single `script` tag **_after_** the `` tag: + + +{@example 'cb-aot-compiler/ts/src/index.html' region='bundle'} + + + +{@a serve} + +## Serve the app + +You'll need a web server to host the application. +Use the same _Lite Server_ employed elsewhere in the documentation: + + npm run lite + + +The server starts, launches a browser, and the app should appear. + + +{@a source-code} + +## AOT QuickStart Source Code + +Here's the pertinent source code: + + + + {@example 'cb-aot-compiler/ts/src/app/app.component.html'} + + + + + {@example 'cb-aot-compiler/ts/src/app/app.component.ts'} + + + + + {@example 'cb-aot-compiler/ts/src/main.ts'} + + + + + {@example 'cb-aot-compiler/ts/src/index.html'} + + + + + {@example 'cb-aot-compiler/ts/tsconfig-aot.json'} + + + + + {@example 'cb-aot-compiler/ts/rollup-config.js'} + + + + + + + +{@a workflow} + +## Workflow and convenience script + +You'll rebuild the AOT version of the application every time you make a change. +Those _npm_ commands are long and difficult to remember. + +Add the following _npm_ convenience script to the `package.json` so you can compile and rollup in one command.Open a terminal window and try it. + + npm run build:aot + + + + + +{@a run-jit} +### And JIT too! + +AOT compilation and rollup together take several seconds. +You may be able to develop iteratively a little faster with SystemJS and JIT. +The same source code can be built both ways. Here's one way to do that. + +* Make a copy of `index.html` and call it `index-jit.html`. +* Delete the script at the bottom of `index-jit.html` that loads `bundle.js` +* Restore the SystemJS scripts like this: + +{@example 'cb-aot-compiler/ts/src/index-jit.html' region='jit'} + +Notice the slight change to the `system.import` which now specifies `src/app/main-jit`. +That's the JIT version of the bootstrap file that we preserved [above](#bootstrap) +Open a _different_ terminal window and enter. + + npm start + + +That compiles the app with JIT and launches the server. +The server loads `index.html` which is still the AOT version (confirm in the browser console). +Change the address bar to `index-jit.html` and it loads the JIT version (confirm in the browser console). + +Develop as usual. +The server and TypeScript compiler are in "watch mode" so your changes are reflected immediately in the browser. + +To see those changes in AOT, switch to the original terminal and re-run `npm run build:aot`. +When it finishes, go back to the browser and back-button to the AOT version in the (default) `index.html`. + +Now you can develop JIT and AOT, side-by-side. + + + +{@a toh} + +## Tour of Heroes + +The sample above is a trivial variation of the QuickStart app. +In this section you apply what you've learned about AOT compilation and Tree Shaking +to an app with more substance, the tutorial [_Tour of Heroes_](../tutorial/toh-pt6.html). + +### JIT in development, AOT in production + +Today AOT compilation and Tree Shaking take more time than is practical for development. That will change soon. +For now, it's best to JIT compile in development and switch to AOT compilation before deploying to production. + +Fortunately, the source code can be compiled either way without change _if_ you account for a few key differences. + +***index.html*** + +The JIT and AOT apps require their own `index.html` files because they setup and launch so differently. + +Here they are for comparison: + + + + + {@example 'toh-6/ts/aot/index.html'} + + + + + {@example 'toh-6/ts/src/index.html'} + + + + + +The JIT version relies on `SystemJS` to load individual modules. +Its scripts appear in its `index.html`. + +The AOT version loads the entire application in a single script, `aot/dist/build.js`. +It does not need `SystemJS`, so that script is absent from its `index.html` + +***main.ts*** + +JIT and AOT applications boot in much the same way but require different Angular libraries to do so. +The key differences, covered in the [Bootstrap](#bootstrap) section above, +are evident in these `main` files which can and should reside in the same folder: + + + + + {@example 'toh-6/ts/src/main-aot.ts'} + + + + + {@example 'toh-6/ts/src/main.ts'} + + + + + +***TypeScript configuration*** + +JIT-compiled applications transpile to `commonjs` modules. +AOT-compiled applications transpile to _ES2015_/_ES6_ modules to facilitate Tree Shaking. +AOT requires its own TypeScript configuration settings as well. + +You'll need separate TypeScript configuration files such as these: + + + + + {@example 'toh-6/ts/tsconfig-aot.json'} + + + + + {@example 'toh-6/ts/src/tsconfig.1.json'} + + + + + + + +~~~ {.callout.is-helpful} + + +
+ @Types and node modules +
+ +In the file structure of _this particular sample project_, +the `node_modules` folder happens to be two levels up from the project root. +Therefore, `"typeRoots"` must be set to `"../../node_modules/@types/"`. + +In a more typical project, `node_modules` would be a sibling of `tsconfig-aot.json` +and `"typeRoots"` would be set to `"node_modules/@types/"`. +Edit your `tsconfig-aot.json` to fit your project's file structure. + + +~~~ + +### Tree Shaking + +Rollup does the Tree Shaking as before. + + +{@example 'toh-6/ts/rollup-config.js'} + +### Running the application + + +~~~ {.alert.is-important} + +The general audience instructions for running the AOT build of the Tour of Heroes app are not ready. + +The following instructions presuppose that you have cloned the +angular.io +github repository and prepared it for development as explained in the repo's README.md. + +The _Tour of Heroes_ source code is in the `public/docs/_examples/toh-6/ts` folder. + +~~~ + +Run the JIT-compiled app with `npm start` as for all other JIT examples. + +Compiling with AOT presupposes certain supporting files, most of them discussed above. + + + + {@example 'toh-6/ts/src/index.html'} + + + + + {@example 'toh-6/ts/copy-dist-files.js'} + + + + + {@example 'toh-6/ts/rollup-config.js'} + + + + + {@example 'toh-6/ts/tsconfig-aot.json'} + + + + + +Extend the `scripts` section of the `package.json` with these npm scripts:Copy the AOT distribution files into the `/aot` folder with the node script: + + node copy-dist-files + + + +You won't do that again until there are updates to `zone.js` or the `core-js` shim for old browsers.Now AOT-compile the app and launch it with the `lite` server: + + npm run build:aot && npm run serve:aot + + + +### Inspect the Bundle + +It's fascinating to see what the generated JavaScript bundle looks like after Rollup. +The code is minified, so you won't learn much from inspecting the bundle directly. +But the source-map-explorer +tool can be quite revealing. + +Install it: + + npm install source-map-explorer --save-dev + + +Run the following command to generate the map. + + + node_modules/.bin/source-map-explorer aot/dist/build.js + + + +The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies, +showing exactly which application and Angular modules and classes are included in the bundle. + +Here's the map for _Tour of Heroes_. + +
+ TOH-6-bundle +
+ +
\ No newline at end of file diff --git a/aio/content/cookbook/component-communication.md b/aio/content/cookbook/component-communication.md new file mode 100644 index 0000000000..f21ab84614 --- /dev/null +++ b/aio/content/cookbook/component-communication.md @@ -0,0 +1,301 @@ +@title +Component Interaction + +@intro +Share information between different directives and components + +@description +This cookbook contains recipes for common component communication scenarios +in which two or more components share information. +## Table of contents + +[Pass data from parent to child with input binding](#parent-to-child) + +[Intercept input property changes with a setter](#parent-to-child-setter) + +[Intercept input property changes with *ngOnChanges*](#parent-to-child-on-changes) + +[Parent listens for child event](#child-to-parent) + +[Parent interacts with child via a *local variable*](#parent-to-child-local-var) + +[Parent calls a *ViewChild*](#parent-to-view-child) + +[Parent and children communicate via a service](#bidirectional-service) +**See the **. + +## Pass data from parent to child with input binding + +`HeroChildComponent` has two ***input properties***, +typically adorned with [@Input decorations](../guide/template-syntax.html#inputs-outputs). + + +{@example 'cb-component-communication/ts/src/app/hero-child.component.ts'} + +The second `@Input` aliases the child component property name `masterName` as `'master'`. + +The `HeroParentComponent` nests the child `HeroChildComponent` inside an `*ngFor` repeater, +binding its `master` string property to the child's `master` alias +and each iteration's `hero` instance to the child's `hero` property. + + +{@example 'cb-component-communication/ts/src/app/hero-parent.component.ts'} + +The running application displays three heroes: + +
+ Parent-to-child +
+ +### Test it + +E2E test that all children were instantiated and displayed as expected: + + +{@example 'cb-component-communication/e2e-spec.ts' region='parent-to-child'} + +[Back to top](#top) + +## Intercept input property changes with a setter + +Use an input property setter to intercept and act upon a value from the parent. + +The setter of the `name` input property in the child `NameChildComponent` +trims the whitespace from a name and replaces an empty value with default text. + + +{@example 'cb-component-communication/ts/src/app/name-child.component.ts'} + +Here's the `NameParentComponent` demonstrating name variations including a name with all spaces: + + +{@example 'cb-component-communication/ts/src/app/name-parent.component.ts'} + + +
+ Parent-to-child-setter +
+ +### Test it + +E2E tests of input property setter with empty and non-empty names: + + +{@example 'cb-component-communication/e2e-spec.ts' region='parent-to-child-setter'} + +[Back to top](#top) + +## Intercept input property changes with *ngOnChanges* + +Detect and act upon changes to input property values with the `ngOnChanges` method of the `OnChanges` lifecycle hook interface. +May prefer this approach to the property setter when watching multiple, interacting input properties. + +Learn about `ngOnChanges` in the [LifeCycle Hooks](../guide/lifecycle-hooks.html) chapter.This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes: + + +{@example 'cb-component-communication/ts/src/app/version-child.component.ts'} + +The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them. + + +{@example 'cb-component-communication/ts/src/app/version-parent.component.ts'} + +Here's the output of a button-pushing sequence: + +
+ Parent-to-child-onchanges +
+ +### Test it + +Test that ***both*** input properties are set initially and that button clicks trigger +the expected `ngOnChanges` calls and values: + + +{@example 'cb-component-communication/e2e-spec.ts' region='parent-to-child-onchanges'} + +[Back to top](#top) + +## Parent listens for child event + +The child component exposes an `EventEmitter` property with which it `emits`events when something happens. +The parent binds to that event property and reacts to those events. + +The child's `EventEmitter` property is an ***output property***, + typically adorned with an [@Output decoration](../guide/template-syntax.html#inputs-outputs) + as seen in this `VoterComponent`: + + +{@example 'cb-component-communication/ts/src/app/voter.component.ts'} + +Clicking a button triggers emission of a `true` or `false` (the boolean *payload*). + +The parent `VoteTakerComponent` binds an event handler (`onVoted`) that responds to the child event +payload (`$event`) and updates a counter. + + +{@example 'cb-component-communication/ts/src/app/votetaker.component.ts'} + +The framework passes the event argument — represented by `$event` — to the handler method, +and the method processes it: + +
+ Child-to-parent +
+ +### Test it + +Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters: + + +{@example 'cb-component-communication/e2e-spec.ts' region='child-to-parent'} + +[Back to top](#top) + +## Parent interacts with child via *local variable* + +A parent component cannot use data binding to read child properties +or invoke child methods. We can do both +by creating a template reference variable for the child element +and then reference that variable *within the parent template* +as seen in the following example. + + +We have a child `CountdownTimerComponent` that repeatedly counts down to zero and launches a rocket. +It has `start` and `stop` methods that control the clock and it displays a +countdown status message in its own template. + +{@example 'cb-component-communication/ts/src/app/countdown-timer.component.ts'} + +Let's see the `CountdownLocalVarParentComponent` that hosts the timer component. + + +{@example 'cb-component-communication/ts/src/app/countdown-parent.component.ts' region='lv'} + +The parent component cannot data bind to the child's +`start` and `stop` methods nor to its `seconds` property. + +We can place a local variable (`#timer`) on the tag (``) representing the child component. +That gives us a reference to the child component itself and the ability to access +*any of its properties or methods* from within the parent template. + +In this example, we wire parent buttons to the child's `start` and `stop` and +use interpolation to display the child's `seconds` property. + +Here we see the parent and child working together. + +
+ countdown timer +
+ + + +{@a countdown-tests} +### Test it + +Test that the seconds displayed in the parent template +match the seconds displayed in the child's status message. +Test also that clicking the *Stop* button pauses the countdown timer: + + +{@example 'cb-component-communication/e2e-spec.ts' region='countdown-timer-tests'} + +[Back to top](#top) + +## Parent calls a *ViewChild* + +The *local variable* approach is simple and easy. But it is limited because +the parent-child wiring must be done entirely within the parent template. +The parent component *itself* has no access to the child. + +We can't use the *local variable* technique if an instance of the parent component *class* +must read or write child component values or must call child component methods. + +When the parent component *class* requires that kind of access, +we ***inject*** the child component into the parent as a *ViewChild*. + +We'll illustrate this technique with the same [Countdown Timer](#countdown-timer-example) example. +We won't change its appearance or behavior. +The child [CountdownTimerComponent](#countdown-timer-example) is the same as well. +We are switching from the *local variable* to the *ViewChild* technique +solely for the purpose of demonstration.Here is the parent, `CountdownViewChildParentComponent`: + +{@example 'cb-component-communication/ts/src/app/countdown-parent.component.ts' region='vc'} + +It takes a bit more work to get the child view into the parent component *class*. + +We import references to the `ViewChild` decorator and the `AfterViewInit` lifecycle hook. + +We inject the child `CountdownTimerComponent` into the private `timerComponent` property +via the `@ViewChild` property decoration. + +The `#timer` local variable is gone from the component metadata. +Instead we bind the buttons to the parent component's own `start` and `stop` methods and +present the ticking seconds in an interpolation around the parent component's `seconds` method. + +These methods access the injected timer component directly. + +The `ngAfterViewInit` lifecycle hook is an important wrinkle. +The timer component isn't available until *after* Angular displays the parent view. +So we display `0` seconds initially. + +Then Angular calls the `ngAfterViewInit` lifecycle hook at which time it is *too late* +to update the parent view's display of the countdown seconds. +Angular's unidirectional data flow rule prevents us from updating the parent view's +in the same cycle. We have to *wait one turn* before we can display the seconds. + +We use `setTimeout` to wait one tick and then revise the `seconds` method so +that it takes future values from the timer component. + +### Test it +Use [the same countdown timer tests](#countdown-tests) as before.[Back to top](#top) + +## Parent and children communicate via a service + +A parent component and its children share a service whose interface enables bi-directional communication +*within the family*. + +The scope of the service instance is the parent component and its children. +Components outside this component subtree have no access to the service or their communications. + +This `MissionService` connects the `MissionControlComponent` to multiple `AstronautComponent` children. + + +{@example 'cb-component-communication/ts/src/app/mission.service.ts'} + +The `MissionControlComponent` both provides the instance of the service that it shares with its children +(through the `providers` metadata array) and injects that instance into itself through its constructor: + + +{@example 'cb-component-communication/ts/src/app/missioncontrol.component.ts'} + +The `AstronautComponent` also injects the service in its constructor. +Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance: + + +{@example 'cb-component-communication/ts/src/app/astronaut.component.ts'} + + +Notice that we capture the `subscription` and unsubscribe when the `AstronautComponent` is destroyed. +This is a memory-leak guard step. There is no actual risk in this app because the +lifetime of a `AstronautComponent` is the same as the lifetime of the app itself. +That *would not* always be true in a more complex application. + +We do not add this guard to the `MissionControlComponent` because, as the parent, +it controls the lifetime of the `MissionService`.The *History* log demonstrates that messages travel in both directions between +the parent `MissionControlComponent` and the `AstronautComponent` children, +facilitated by the service: + +
+ bidirectional-service +
+ +### Test it + +Tests click buttons of both the parent `MissionControlComponent` and the `AstronautComponent` children +and verify that the *History* meets expectations: + + +{@example 'cb-component-communication/e2e-spec.ts' region='bidirectional-service'} + +[Back to top](#top) \ No newline at end of file diff --git a/aio/content/cookbook/component-relative-paths.md b/aio/content/cookbook/component-relative-paths.md index ecace6d84c..13952d743a 100644 --- a/aio/content/cookbook/component-relative-paths.md +++ b/aio/content/cookbook/component-relative-paths.md @@ -11,7 +11,8 @@ Our components often refer to external template and style files. We identify those files with a URL in the `templateUrl` and `styleUrls` properties of the `@Component` metadata as seen here: -{@example 'cb-component-relative-paths/ts/app/some.component.ts' -region='absolute-config' -linenums='false' } + +{@example 'cb-component-relative-paths/ts/src/app/some.component.ts' region='absolute-config'} By default, we *must* specify the full path back to the application root. We call this an ***absolute path*** because it is *absolute* with respect to the application root. @@ -20,13 +21,14 @@ There are two problems with an *absolute path*: 1. We have to remember the full path back to the application root. -2. We have to update the URL when we move the component around in the application files structure. +1. We have to update the URL when we move the component around in the application files structure. It would be much easier to write and maintain our application components if we could specify template and style locations *relative* to their component class file. *We can!* + ~~~ {.alert.is-important} We can if we build our application as `commonjs` modules and load those modules @@ -38,27 +40,44 @@ The Angular CLI uses these technologies and defaults to the CLI users can skip this chapter or read on to understand how it works. + ~~~ + ## _Component-Relative_ Paths -Our goal is to specify template and style URLs *relative* to their component class files, +Our goal is to specify template and style URLs *relative* to their component class files, hence the term ***component-relative path***. The key to success is following a convention that puts related component files in well-known locations. We recommend keeping component template and component-specific style files as *siblings* of their -companion component class files. -Here we see the three files for `SomeComponent` sitting next to each other in the `app` folder. +companion component class files. +Here we see the three files for `SomeComponent` sitting next to each other in the `app` folder. + + + + + app + + some.component.css + + + + + some.component.html + + + + + some.component.ts + + - - app - some.component.css - some.component.html - some.component.ts - ... - + + + We'll have more files and folders — and greater folder depth — as our application grows. We'll be fine as long as the component files travel together as the inseparable siblings they are. @@ -68,16 +87,19 @@ We'll be fine as long as the component files travel together as the inseparable Having adopted this file structure convention, we can specify locations of the template and style files relative to the component class file simply by setting the `moduleId` property of the `@Component` metadata like this -{@example 'cb-component-relative-paths/ts/app/some.component.ts' -region='module-id' -linenums='false'} +{@example 'cb-component-relative-paths/ts/src/app/some.component.ts' region='module-id'} -We strip the `app/` base path from the `templateUrl` and `styleUrls` and replace it with `./`. +We strip the `src/app/` base path from the `templateUrl` and `styleUrls` and replace it with `./`. The result looks like this: -{@example 'cb-component-relative-paths/ts/app/some.component.ts' -region='relative-config' -linenums='false'} +{@example 'cb-component-relative-paths/ts/src/app/some.component.ts' region='relative-config'} + + ~~~ {.alert.is-helpful} - Webpack users may prefer [an alternative approach](#webpack). +Webpack users may prefer [an alternative approach](#webpack). + ~~~ @@ -87,21 +109,30 @@ The result looks like this: **We can see the ** and download the source code from there or simply read the pertinent source here. + - - - {@example 'cb-component-relative-paths/ts/app/some.component.ts'} + + {@example 'cb-component-relative-paths/ts/src/app/some.component.ts'} - - {@example 'cb-component-relative-paths/ts/app/some.component.html'} + + + + {@example 'cb-component-relative-paths/ts/src/app/some.component.html'} - - {@example 'cb-component-relative-paths/ts/app/some.component.css'} + + + + {@example 'cb-component-relative-paths/ts/src/app/some.component.css'} - - {@example 'cb-component-relative-paths/ts/app/app.component.ts'} + + + + {@example 'cb-component-relative-paths/ts/src/app/app.component.ts'} - + + + + {@a why-default} @@ -118,15 +149,15 @@ First, let's look at what happens if we use a relative path and omit the `module Angular can't find the file so it throws an error. -Why can't Angular calculate the template and style URLs from the component file's location? +Why can't Angular calculate the template and style URLs from the component file's location? Because the location of the component can't be determined without the developer's help. Angular apps can be loaded in many ways: from individual files, from SystemJS packages, or -from CommonJS packages, to name a few. -We might generate modules in any of several formats. +from CommonJS packages, to name a few. +We might generate modules in any of several formats. We might not be writing modular code at all! -With this diversity of packaging and module load strategies, +With this diversity of packaging and module load strategies, it's not possible for Angular to know with certainty where these files reside at runtime. The only location Angular can be sure of is the URL of the `index.html` home page, the application root. @@ -142,7 +173,8 @@ the absolute URL of the component class module file. That knowledge enables us to tell Angular where the *component* file is by setting the `moduleId`: -{@example 'cb-component-relative-paths/ts/app/some.component.ts' -region='module-id' -linenums='false'} +{@example 'cb-component-relative-paths/ts/src/app/some.component.ts' region='module-id'} + {@a webpack} @@ -153,8 +185,10 @@ Webpack developers have an alternative to `moduleId`. They can load templates and styles at runtime by adding `./` at the beginning of the `template` and `styles` / `styleUrls` properties that reference *component-relative URLS. -{@example 'webpack/ts/src/app/app.component.ts' --linenums='false'} + +{@example 'webpack/ts/src/app/app.component.ts'} + Webpack will do a `require` behind the scenes to load the templates and styles. Read more [here](../guide/webpack.html#highlights). -See the [Introduction to Webpack](../guide/webpack.html). +See the [Introduction to Webpack](../guide/webpack.html). \ No newline at end of file diff --git a/aio/content/cookbook/dependency-injection.md b/aio/content/cookbook/dependency-injection.md new file mode 100644 index 0000000000..694f3ff44b --- /dev/null +++ b/aio/content/cookbook/dependency-injection.md @@ -0,0 +1,921 @@ +@title +Dependency Injection + +@intro +Techniques for Dependency Injection + +@description +Dependency Injection is a powerful pattern for managing code dependencies. +In this cookbook we will explore many of the features of Dependency Injection (DI) in Angular. +## Table of contents + +[Application-wide dependencies](#app-wide-dependencies) + +[External module configuration](#external-module-configuration) + +[*@Injectable* and nested service dependencies](#nested-dependencies) + +[Limit service scope to a component subtree](#service-scope) + +[Multiple service instances (sandboxing)](#multiple-service-instances) + +[Qualify dependency lookup with *@Optional* and *@Host*](#qualify-dependency-lookup) + +[Inject the component's DOM element](#component-element) + +[Define dependencies with providers](#providers) +* [The *provide* object literal](#provide) +* [useValue - the *value provider*](#usevalue) +* [useClass - the *class provider*](#useclass) +* [useExisting - the *alias provider*](#useexisting) +* [useFactory - the *factory provider*](#usefactory) + +[Provider token alternatives](#tokens) +* [class-interface](#class-interface) +* [OpaqueToken](#opaque-token) + +[Inject into a derived class](#di-inheritance) + +[Find a parent component by injection](#find-parent) + * [Find parent with a known component type](#known-parent) + * [Cannot find a parent by its base class](#base-parent) + * [Find a parent by its class-interface](#class-interface-parent) + * [Find a parent in a tree of parents (*@SkipSelf*)](#parent-tree) + * [A *provideParent* helper function](#provideparent) + +[Break circularities with a forward class reference (*forwardRef*)](#forwardref) +**See the ** +of the code supporting this cookbook. + +## Application-wide dependencies +Register providers for dependencies used throughout the application in the root application component, `AppComponent`. + +In the following example, we import and register several services +(the `LoggerService`, `UserContext`, and the `UserService`) +in the `@Component` metadata `providers` array. + + +{@example 'cb-dependency-injection/ts/src/app/app.component.ts' region='import-services'} + +All of these services are implemented as classes. +Service classes can act as their own providers which is why listing them in the `providers` array +is all the registration we need. +A *provider* is something that can create or deliver a service. +Angular creates a service instance from a class provider by "new-ing" it. +Learn more about providers [below](#providers).Now that we've registered these services, +Angular can inject them into the constructor of *any* component or service, *anywhere* in the application. + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='ctor'} + + + +{@example 'cb-dependency-injection/ts/src/app/user-context.service.ts' region='ctor'} + + +## External module configuration +We often register providers in the `NgModule` rather than in the root application component. + +We do this when (a) we expect the service to be injectable everywhere +or (b) we must configure another application global service _before it starts_. + +We see an example of the second case here, where we configure the Component Router with a non-default +[location strategy](../guide/router.html#location-strategy) by listing its provider +in the `providers` list of the `AppModule`. + + +{@example 'cb-dependency-injection/ts/src/app/app.module.ts' region='providers'} + + + +{@a injectable} + + +{@a nested-dependencies} + +## *@Injectable* and nested service dependencies +The consumer of an injected service does not know how to create that service. +It shouldn't care. +It's the dependency injection's job to create and cache that service. + +Sometimes a service depends on other services ... which may depend on yet other services. +Resolving these nested dependencies in the correct order is also the framework's job. +At each step, the consumer of dependencies simply declares what it requires in its constructor and the framework takes over. + +For example, we inject both the `LoggerService` and the `UserContext` in the `AppComponent`. + +{@example 'cb-dependency-injection/ts/src/app/app.component.ts' region='ctor'} + +The `UserContext` in turn has dependencies on both the `LoggerService` (again) and +a `UserService` that gathers information about a particular user. + + +{@example 'cb-dependency-injection/ts/src/app/user-context.service.ts' region='injectables'} + +When Angular creates an`AppComponent`, the dependency injection framework creates an instance of the `LoggerService` and +starts to create the `UserContextService`. +The `UserContextService` needs the `LoggerService`, which the framework already has, and the `UserService`, which it has yet to create. +The `UserService` has no dependencies so the dependency injection framework can just `new` one into existence. + +The beauty of dependency injection is that the author of `AppComponent` didn't care about any of this. +The author simply declared what was needed in the constructor (`LoggerService` and `UserContextService`) and the framework did the rest. + +Once all the dependencies are in place, the `AppComponent` displays the user information: + +
+ Logged In User +
+ +### *@Injectable()* +Notice the `@Injectable()`decorator on the `UserContextService` class. + +{@example 'cb-dependency-injection/ts/src/app/user-context.service.ts' region='injectable'} + +That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`. + +Technically, the `@Injectable()`decorator is only _required_ for a service class that has _its own dependencies_. +The `LoggerService` doesn't depend on anything. The logger would work if we omitted `@Injectable()` +and the generated code would be slightly smaller. + +But the service would break the moment we gave it a dependency and we'd have to go back and +and add `@Injectable()` to fix it. We add `@Injectable()` from the start for the sake of consistency and to avoid future pain. + + +~~~ {.alert.is-helpful} + +Although we recommend applying `@Injectable` to all service classes, do not feel bound by it. +Some developers prefer to add it only where needed and that's a reasonable policy too. + + +~~~ + + +The `AppComponent` class had two dependencies as well but no `@Injectable()`. +It didn't need `@Injectable()` because that component class has the `@Component` decorator. +In Angular with TypeScript, a *single* decorator — *any* decorator — is sufficient to identify dependency types. + + +## Limit service scope to a component subtree + +All injected service dependencies are singletons meaning that, +for a given dependency injector ("injector"), there is only one instance of service. + +But an Angular application has multiple dependency injectors, arranged in a tree hierarchy that parallels the component tree. +So a particular service can be *provided* (and created) at any component level and multiple times +if provided in multiple components. + +By default, a service dependency provided in one component is visible to all of its child components and +Angular injects the same service instance into all child components that ask for that service. + +Accordingly, dependencies provided in the root `AppComponent` can be injected into *any* component *anywhere* in the application. + +That isn't always desirable. +Sometimes we want to restrict service availability to a particular region of the application. + +We can limit the scope of an injected service to a *branch* of the application hierarchy +by providing that service *at the sub-root component for that branch*. +Here we provide the `HeroService` to the `HeroesBaseComponent` by listing it in the `providers` array: + +{@example 'cb-dependency-injection/ts/src/app/sorted-heroes.component.ts' region='injection'} + +When Angular creates the `HeroesBaseComponent`, it also creates a new instance of `HeroService` +that is visible only to the component and its children (if any). + +We could also provide the `HeroService` to a *different* component elsewhere in the application. +That would result in a *different* instance of the service, living in a *different* injector. +We examples of such scoped `HeroService` singletons appear throughout the accompanying sample code, +including the `HeroBiosComponent`, `HeroOfTheMonthComponent`, and `HeroesBaseComponent`. +Each of these components has its own `HeroService` instance managing its own independent collection of heroes. + + + +~~~ {.alert.is-helpful} + +### Take a break! +This much Dependency Injection knowledge may be all that many Angular developers +ever need to build their applications. It doesn't always have to be more complicated. + + +~~~ + + +## Multiple service instances (sandboxing) + +Sometimes we want multiple instances of a service at *the same level of the component hierarchy*. + +A good example is a service that holds state for its companion component instance. +We need a separate instance of the service for each component. +Each service has its own work-state, isolated from the service-and-state of a different component. +We call this *sandboxing* because each service and component instance has its own sandbox to play in. + + +Imagine a `HeroBiosComponent` that presents three instances of the `HeroBioComponent`. + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='simple'} + +Each `HeroBioComponent` can edit a single hero's biography. +A `HeroBioComponent` relies on a `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero. + +{@example 'cb-dependency-injection/ts/src/app/hero-cache.service.ts' region='service'} + +Clearly the three instances of the `HeroBioComponent` can't share the same `HeroCacheService`. +They'd be competing with each other to determine which hero to cache. + +Each `HeroBioComponent` gets its *own* `HeroCacheService` instance +by listing the `HeroCacheService` in its metadata `providers` array. + +{@example 'cb-dependency-injection/ts/src/app/hero-bio.component.ts' region='component'} + +The parent `HeroBiosComponent` binds a value to the `heroId`. +The `ngOnInit` pass that `id` to the service which fetches and caches the hero. +The getter for the `hero` property pulls the cached hero from the service. +And the template displays this data-bound property. + +Find this example in live code +and confirm that the three `HeroBioComponent` instances have their own cached hero data. +
+ Bios +
+ + + +{@a optional} + + +{@a qualify-dependency-lookup} + +## Qualify dependency lookup with *@Optional* and *@Host* +We learned that dependencies can be registered at any level in the component hierarchy. + +When a component requests a dependency, Angular starts with that component's injector and walks up the injector tree +until it finds the first suitable provider. Angular throws an error if it can't find the dependency during that walk. + +We *want* this behavior most of the time. +But sometimes we need to limit the search and/or accommodate a missing dependency. +We can modify Angular's search behavior with the `@Host` and `@Optional` qualifying decorators, +used individually or together. + +The `@Optional` decorator tells Angular to continue when it can't find the dependency. +Angular sets the injection parameter to `null` instead. + +The `@Host` decorator stops the upward search at the *host component*. + +The host component is typically the component requesting the dependency. +But when this component is projected into a *parent* component, that parent component becomes the host. +We look at this second, more interesting case in our next example. + +### Demonstration +The `HeroBiosAndContactsComponent` is a revision of the `HeroBiosComponent` that we looked at [above](#hero-bios-component). + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='hero-bios-and-contacts'} + +Focus on the template: + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='template'} + +We've inserted a `` element between the `` tags. +Angular *projects* (*transcludes*) the corresponding `HeroContactComponent` into the `HeroBioComponent` view, +placing it in the `` slot of the `HeroBioComponent` template: + +{@example 'cb-dependency-injection/ts/src/app/hero-bio.component.ts' region='template'} + +It looks like this, with the hero's telephone number from `HeroContactComponent` projected above the hero description: +
+ bio and contact +
+ +Here's the `HeroContactComponent` which demonstrates the qualifying decorators that we're talking about in this section: + +{@example 'cb-dependency-injection/ts/src/app/hero-contact.component.ts' region='component'} + +Focus on the constructor parameters + +{@example 'cb-dependency-injection/ts/src/app/hero-contact.component.ts' region='ctor-params'} + +The `@Host()` function decorating the `heroCache` property ensures that +we get a reference to the cache service from the parent `HeroBioComponent`. +Angular throws if the parent lacks that service, even if a component higher in the component tree happens to have that service. + +A second `@Host()` function decorates the `loggerService` property. +We know the only `LoggerService` instance in the app is provided at the `AppComponent` level. +The host `HeroBioComponent` doesn't have its own `LoggerService` provider. + +Angular would throw an error if we hadn't also decorated the property with the `@Optional()` function. +Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest of the component adapts. + +We'll come back to the `elementRef` property shortly.Here's the `HeroBiosAndContactsComponent` in action. +
+ Bios with contact into +
+ +If we comment out the `@Host()` decorator, Angular now walks up the injector ancestor tree +until it finds the logger at the `AppComponent` level. The logger logic kicks in and the hero display updates +with the gratuitous "!!!", indicating that the logger was found. +
+ Without @Host +
+ +On the other hand, if we restore the `@Host()` decorator and comment out `@Optional`, +the application fails for lack of the required logger at the host component level. +
+`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)` +## Inject the component's element + +On occasion we might need to access a component's corresponding DOM element. +Although we strive to avoid it, many visual effects and 3rd party tools (such as jQuery) +require DOM access. + +To illustrate, we've written a simplified version of the `HighlightDirective` from +the [Attribute Directives](../guide/attribute-directives.html) chapter. + +{@example 'cb-dependency-injection/ts/src/app/highlight.directive.ts'} + +The directive sets the background to a highlight color when the user mouses over the +DOM element to which it is applied. + +Angular set the constructor's `el` parameter to the injected `ElementRef` which is +a wrapper around that DOM element. +Its `nativeElement` property exposes the DOM element for the directive to manipulate. + +The sample code applies the directive's `myHighlight` attribute to two `
` tags, +first without a value (yielding the default color) and then with an assigned color value. + +{@example 'cb-dependency-injection/ts/src/app/app.component.html' region='highlight'} + +The following image shows the effect of mousing over the `` tag. +
+ Highlighted bios +
+ + +## Define dependencies with providers + +In this section we learn to write providers that deliver dependent services. + +### Background +We get a service from a dependency injector by giving it a ***token***. + +We usually let Angular handle this transaction for us by specifying a constructor parameter and its type. +The parameter type serves as the injector lookup *token*. +Angular passes this token to the injector and assigns the result to the parameter. +Here's a typical example: + + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='ctor'} + +Angular asks the injector for the service associated with the `LoggerService` and +and assigns the returned value to the `logger` parameter. + +Where did the injector get that value? +It may already have that value in its internal container. +If it doesn't, it may be able to make one with the help of a ***provider***. +A *provider* is a recipe for delivering a service associated with a *token*. +If the injector doesn't have a provider for the requested *token*, it delegates the request +to its parent injector, where the process repeats until there are no more injectors. +If the search is futile, the injector throws an error ... unless the request was [optional](#optional). + +Let's return our attention to providers themselves.A new injector has no providers. +Angular initializes the injectors it creates with some providers it cares about. +We have to register our _own_ application providers manually, +usually in the `providers` array of the `Component` or `Directive` metadata: + +{@example 'cb-dependency-injection/ts/src/app/app.component.ts' region='providers'} + +### Defining providers + +The simple class provider is the most typical by far. +We mention the class in the `providers` array and we're done. + +{@example 'cb-dependency-injection/ts/src/app/hero-bios.component.ts' region='class-provider'} + +It's that simple because the most common injected service is an instance of a class. +But not every dependency can be satisfied by creating a new instance of a class. +We need other ways to deliver dependency values and that means we need other ways to specify a provider. + +The `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why we need them. + +
+ Hero of the month +
+ +It's visually simple: a few properties and the output of a logger. The code behind it gives us plenty to talk about. + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='hero-of-the-month'} + + + + +{@a provide} +#### The *provide* object literal + +The `provide` object literal takes a *token* and a *definition object*. +The *token* is usually a class but [it doesn't have to be](#tokens). + +The *definition* object has one main property, (e.g. `useValue`) that indicates how the provider +should create or return the provided value. + + + +{@a usevalue} +#### useValue - the *value provider* + +Set the `useValue` property to a ***fixed value*** that the provider can return as the dependency object. + +Use this technique to provide *runtime configuration constants* such as web-site base addresses and feature flags. +We often use a *value provider* in a unit test to replace a production service with a fake or mock. + +The `HeroOfTheMonthComponent` example has two *value providers*. +The first provides an instance of the `Hero` class; +the second specifies a literal string resource: + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='use-value'} + +The `Hero` provider token is a class which makes sense because the value is a `Hero` +and the consumer of the injected hero would want the type information. + +The `TITLE` provider token is *not a class*. +It's a special kind of provider lookup key called an [OpaqueToken](#opaquetoken). +We often use an `OpaqueToken` when the dependency is a simple value like a string, a number, or a function. + +The value of a *value provider* must be defined *now*. We can't create the value later. +Obviously the title string literal is immediately available. +The `someHero` variable in this example was set earlier in the file: + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='some-hero'} + +The other providers create their values *lazily* when they're needed for injection. + + + +{@a useclass} +#### useClass - the *class provider* + +The `useClass` provider creates and returns new instance of the specified class. + +Use this technique to ***substitute an alternative implementation*** for a common or default class. +The alternative could implement a different strategy, extend the default class, +or fake the behavior of the real class in a test case. + +We see two examples in the `HeroOfTheMonthComponent`: + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='use-class'} + +The first provider is the *de-sugared*, expanded form of the most typical case in which the +class to be created (`HeroService`) is also the provider's injection token. +We wrote it in this long form to de-mystify the preferred short form. + +The second provider substitutes the `DateLoggerService` for the `LoggerService`. +The `LoggerService` is already registered at the `AppComponent` level. +When _this component_ requests the `LoggerService`, it receives the `DateLoggerService` instead. +This component and its tree of child components receive the `DateLoggerService` instance. +Components outside the tree continue to receive the original `LoggerService` instance.The `DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message: + +{@example 'cb-dependency-injection/ts/src/app/date-logger.service.ts' region='date-logger-service'} + + + + +{@a useexisting} +#### useExisting - the *alias provider* + +The `useExisting` provider maps one token to another. +In effect, the first token is an ***alias*** for the service associated with second token, +creating ***two ways to access the same service object***. + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='use-existing'} + +Narrowing an API through an aliasing interface is _one_ important use case for this technique. +We're aliasing for that very purpose here. +Imagine that the `LoggerService` had a large API (it's actually only three methods and a property). +We want to shrink that API surface to just the two members exposed by the `MinimalLogger` [*class-interface*](#class-interface): + + +{@example 'cb-dependency-injection/ts/src/app/date-logger.service.ts' region='minimal-logger'} + +The constructor's `logger` parameter is typed as `MinimalLogger` so only its two members are visible in TypeScript: +
+ MinimalLogger restricted API +
+ +Angular actually sets the `logger` parameter to the injector's full version of the `LoggerService` +which happens to be the `DateLoggerService` thanks to the override provider registered previously via `useClass`. +The following image, which displays the logging date, confirms the point: +
+ DateLoggerService entry +
+ + + + +{@a usefactory} +#### useFactory - the *factory provider* + +The `useFactory` provider creates a dependency object by calling a factory function +as seen in this example. + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='use-factory'} + +Use this technique to ***create a dependency object*** +with a factory function whose inputs are some ***combination of injected services and local state***. + +The *dependency object* doesn't have to be a class instance. It could be anything. +In this example, the *dependency object* is a string of the names of the runners-up +to the "Hero of the Month" contest. + +The local state is the number `2`, the number of runners-up this component should show. +We execute `runnersUpFactory` immediately with `2`. + +The `runnersUpFactory` itself isn't the provider factory function. +The true provider factory function is the function that `runnersUpFactory` returns. + + +{@example 'cb-dependency-injection/ts/src/app/runners-up.ts' region='factory-synopsis'} + +That returned function takes a winning `Hero` and a `HeroService` as arguments. + +Angular supplies these arguments from injected values identified by +the two *tokens* in the `deps` array. +The two `deps` values are *tokens* that the injector uses +to provide these factory function dependencies. + +After some undisclosed work, the function returns the string of names +and Angular injects it into the `runnersUp` parameter of the `HeroOfTheMonthComponent`. + +The function retrieves candidate heroes from the `HeroService`, +takes `2` of them to be the runners-up, and returns their concatenated names. +Look at the +for the full source code. + + +{@a tokens} + +## Provider token alternatives: the *class-interface* and *OpaqueToken* + +Angular dependency injection is easiest when the provider *token* is a class +that is also the type of the returned dependency object (what we usually call the *service*). + +But the token doesn't have to be a class and even when it is a class, +it doesn't have to be the same type as the returned object. +That's the subject of our next section. + + +### class-interface +In the previous *Hero of the Month* example, we used the `MinimalLogger` class +as the token for a provider of a `LoggerService`. + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='use-existing'} + +The `MinimalLogger` is an abstract class. + +{@example 'cb-dependency-injection/ts/src/app/date-logger.service.ts' region='minimal-logger'} + +We usually inherit from an abstract class. +But `LoggerService` doesn't inherit from `MinimalLogger`. *No class* inherits from it. +Instead, we use it like an interface. + +Look again at the declaration for `DateLoggerService` + +{@example 'cb-dependency-injection/ts/src/app/date-logger.service.ts' region='date-logger-service-signature'} + +`DateLoggerService` inherits (extends) from `LoggerService`, not `MinimalLogger`. +The `DateLoggerService` *implements* `MinimalLogger` as if `MinimalLogger` were an *interface*. + +We call a class used in this way a ***class-interface***. +The key benefit of a *class-interface* is that we can get the strong-typing of an interface +and we can ***use it as a provider token*** in the same manner as a normal class. + +A ***class-interface*** should define *only* the members that its consumers are allowed to call. +Such a narrowing interface helps decouple the concrete class from its consumers. +The `MinimalLogger` defines just two of the `LoggerClass` members. + +#### Why *MinimalLogger* is a class and not an interface +We can't use an interface as a provider token because +interfaces are not JavaScript objects. +They exist only in the TypeScript design space. +They disappear after the code is transpiled to JavaScript. + +A provider token must be a real JavaScript object of some kind: +a function, an object, a string ... a class. + +Using a class as an interface gives us the characteristics of an interface in a JavaScript object. + +The minimize memory cost, the class should have *no implementation*. +The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript: + +{@example 'cb-dependency-injection/ts/src/app/date-logger.service.ts' region='minimal-logger-transpiled'} + +It never grows larger no matter how many members we add *as long as they are typed but not implemented*. + + +{@a opaque-token} +### OpaqueToken + +Dependency objects can be simple values like dates, numbers and strings or +shapeless objects like arrays and functions. + +Such objects don't have application interfaces and therefore aren't well represented by a class. +They're better represented by a token that is both unique and symbolic, +a JavaScript object that has a friendly name but won't conflict with +another token that happens to have the same name. + +The `OpaqueToken` has these characteristics. +We encountered them twice in the *Hero of the Month* example, +in the *title* value provider and in the *runnersUp* factory provider. + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='provide-opaque-token'} + +We created the `TITLE` token like this: + +{@example 'cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts' region='opaque-token'} + + + +{@a di-inheritance} + +## Inject into a derived class +We must take care when writing a component that inherits from another component. +If the base component has injected dependencies, +we must re-provide and re-inject them in the derived class +and then pass them down to the base class through the constructor. + +In this contrived example, `SortedHeroesComponent` inherits from `HeroesBaseComponent` +to display a *sorted* list of heroes. + +
+ Sorted Heroes +
+ +The `HeroesBaseComponent` could stand on its own. +It demands its own instance of the `HeroService` to get heroes +and displays them in the order they arrive from the database. + + +{@example 'cb-dependency-injection/ts/src/app/sorted-heroes.component.ts' region='heroes-base'} + + +We strongly prefer simple constructors. They should do little more than initialize variables. +This rule makes the component safe to construct under test without fear that it will do something dramatic like talk to the server. +That's why we call the `HeroService` from within the `ngOnInit` rather than the constructor. + +We explain the mysterious `afterGetHeroes` below.Users want to see the heroes in alphabetical order. +Rather than modify the original component, we sub-class it and create a +`SortedHeroesComponent` that sorts the heroes before presenting them. +The `SortedHeroesComponent` lets the base class fetch the heroes. +(we said it was contrived). + +Unfortunately, Angular cannot inject the `HeroService` directly into the base class. +We must provide the `HeroService` again for *this* component, +then pass it down to the base class inside the constructor. + + +{@example 'cb-dependency-injection/ts/src/app/sorted-heroes.component.ts' region='sorted-heroes'} + +Now take note of the `afterGetHeroes` method. +Our first instinct was to create an `ngOnInit` method in `SortedHeroesComponent` and do the sorting there. +But Angular calls the *derived* class's `ngOnInit` *before* calling the base class's `ngOnInit` +so we'd be sorting the heroes array *before they arrived*. That produces a nasty error. + +Overriding the base class's `afterGetHeroes` method solves the problem + +These complications argue for *avoiding component inheritance*. + + +{@a find-parent} + +## Find a parent component by injection + +Application components often need to share information. +We prefer the more loosely coupled techniques such as data binding and service sharing. +But sometimes it makes sense for one component to have a direct reference to another component +perhaps to access values or call methods on that component. + +Obtaining a component reference is a bit tricky in Angular. +Although an Angular application is a tree of components, +there is no public API for inspecting and traversing that tree. + +There is an API for acquiring a child reference +(checkout `Query`, `QueryList`, `ViewChildren`, and `ContentChildren`). + +There is no public API for acquiring a parent reference. +But because every component instance is added to an injector's container, +we can use Angular dependency injection to reach a parent component. + +This section describes some techniques for doing that. + + +### Find a parent component of known type + +We use standard class injection to acquire a parent component whose type we know. + +In the following example, the parent `AlexComponent` has several children including a `CathyComponent`: + +{@a alex} + + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-1'} + +*Cathy* reports whether or not she has access to *Alex* +after injecting an `AlexComponent` into her constructor: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='cathy'} + +We added the [@Optional](#optional) qualifier for safety but +the +confirms that the `alex` parameter is set. + + +### Cannot find a parent by its base class + +What if we do *not* know the concrete parent component class? + +A re-usable component might be a child of multiple components. +Imagine a component for rendering breaking news about a financial instrument. +For sound (cough) business reasons, this news component makes frequent calls +directly into its parent instrument as changing market data stream by. + +The app probably defines more than a dozen financial instrument components. +If we're lucky, they all implement the same base class +whose API our `NewsComponent` understands. + +Looking for components that implement an interface would be better. +That's not possible because TypeScript interfaces disappear from the transpiled JavaScript +which doesn't support interfaces. There's no artifact we could look for.We're not claiming this is good design. +We are asking *can a component inject its parent via the parent's base class*? + +The sample's `CraigComponent` explores this question. [Looking back](#alex) +we see that the `Alex` component *extends* (*inherits*) from a class named `Base`. + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-class-signature'} + +The `CraigComponent` tries to inject `Base` into its `alex` constructor parameter and reports if it succeeded. + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='craig'} + +Unfortunately, this does not work. +The +confirms that the `alex` parameter is null. +*We cannot inject a parent by its base class.* + + +### Find a parent by its class-interface + +We can find a parent component with a [class-interface](#class-interface). + +The parent must cooperate by providing an *alias* to itself in the name of a *class-interface* token. + +Recall that Angular always adds a component instance to its own injector; +that's why we could inject *Alex* into *Cathy* [earlier](#known-parent). + +We write an [*alias provider*](#useexisting) — a `provide` object literal with a `useExisting` definition — +that creates an *alternative* way to inject the same component instance +and add that provider to the `providers` array of the `@Component` metadata for the `AlexComponent`: + +{@a alex-providers} + + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-providers'} + +[Parent](#parent-token) is the provider's *class-interface* token. +The [*forwardRef*](#forwardref) breaks the circular reference we just created by having the `AlexComponent` refer to itself. + +*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter, the same way we've done it before: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='carol-class'} + +Here's *Alex* and family in action: +
+ Alex in action +
+ + + +{@a parent-tree} +### Find the parent in a tree of parents + +Imagine one branch of a component hierarchy: *Alice* -> *Barry* -> *Carol*. +Both *Alice* and *Barry* implement the `Parent` *class-interface*. + +*Barry* is the problem. He needs to reach his parent, *Alice*, and also be a parent to *Carol*. +That means he must both *inject* the `Parent` *class-interface* to get *Alice* and +*provide* a `Parent` to satisfy *Carol*. + +Here's *Barry*: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='barry'} + +*Barry*'s `providers` array looks just like [*Alex*'s](#alex-providers). +If we're going to keep writing [*alias providers*](#useexisting) like this we should create a [helper function](#provideparent). + +For now, focus on *Barry*'s constructor: + + + + {@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='barry-ctor'} + + + + + {@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='carol-ctor'} + + + + + +It's identical to *Carol*'s constructor except for the additional `@SkipSelf` decorator. + +`@SkipSelf` is essential for two reasons: + +1. It tells the injector to start its search for a `Parent` dependency in a component *above* itself, +which *is* what parent means. + +2. Angular throws a cyclic dependency error if we omit the `@SkipSelf` decorator. + + `Cannot instantiate cyclic dependency! (BethComponent -> Parent -> BethComponent)` + +Here's *Alice*, *Barry* and family in action: + +
+ Alice in action +
+ + + +{@a parent-token} +### The *Parent* class-interface +We [learned earlier](#class-interface) that a *class-interface* is an abstract class used as an interface rather than as a base class. + +Our example defines a `Parent` *class-interface* . + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='parent'} + +The `Parent` *class-interface* defines a `name` property with a type declaration but *no implementation*., +The `name` property is the only member of a parent component that a child component can call. +Such a narrowing interface helps decouple the child component class from its parent components. + +A component that could serve as a parent *should* implement the *class-interface* as the `AliceComponent` does: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alice-class-signature'} + +Doing so adds clarity to the code. But it's not technically necessary. +Although the `AlexComponent` has a `name` property (as required by its `Base` class) +its class signature doesn't mention `Parent`: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-class-signature'} + + +The `AlexComponent` *should* implement `Parent` as a matter of proper style. +It doesn't in this example *only* to demonstrate that the code will compile and run without the interface + + +{@a provideparent} +### A *provideParent* helper function + +Writing variations of the same parent *alias provider* gets old quickly, +especially this awful mouthful with a [*forwardRef*](#forwardref): + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-providers'} + +We can extract that logic into a helper function like this: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='provide-the-parent'} + +Now we can add a simpler, more meaningful parent provider to our components: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alice-providers'} + +We can do better. The current version of the helper function can only alias the `Parent` *class-interface*. +Our application might have a variety of parent types, each with its own *class-interface* token. + +Here's a revised version that defaults to `parent` but also accepts an optional second parameter for a different parent *class-interface*. + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='provide-parent'} + +And here's how we could use it with a different parent type: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='beth-providers'} + + + +{@a forwardref} + +## Break circularities with a forward class reference (*forwardRef*) + +The order of class declaration matters in TypeScript. +We can't refer directly to a class until it's been defined. + +This isn't usually a problem, especially if we adhere to the recommended *one class per file* rule. +But sometimes circular references are unavoidable. +We're in a bind when class 'A refers to class 'B' and 'B' refers to 'A'. +One of them has to be defined first. + +The Angular `forwardRef` function creates an *indirect* reference that Angular can resolve later. + +The *Parent Finder* sample is full of circular class references that are impossible to break. +We face this dilemma when a class makes *a reference to itself* +as does the `AlexComponent` in its `providers` array. +The `providers` array is a property of the `@Component` decorator function which must +appear *above* the class definition. + +We break the circularity with `forwardRef`: + +{@example 'cb-dependency-injection/ts/src/app/parent-finder.component.ts' region='alex-providers'} + diff --git a/aio/content/cookbook/dynamic-component-loader.md b/aio/content/cookbook/dynamic-component-loader.md new file mode 100644 index 0000000000..f7524fc887 --- /dev/null +++ b/aio/content/cookbook/dynamic-component-loader.md @@ -0,0 +1,138 @@ +@title +Dynamic Component Loader + +@intro +Load components dynamically + +@description +Component templates are not always fixed. An application may need to load new components at runtime. + +In this cookbook we show how to use `ComponentFactoryResolver` to add components dynamically. + +## Table of contents + + [Dynamic Component Loading](#dynamic-loading) + + [Where to load the component](#where-to-load) + + [Loading components](#loading-components) + +## Dynamic Component Loading + +The following example shows how to build a dynamic ad banner. + +The hero agency is planning an ad campaign with several different ads cycling through the banner. + +New ad components are added frequently by several different teams. This makes it impractical to use a template with a static component structure. + +Instead we need a way to load a new component without a fixed reference to the component in the ad banner's template. + +Angular comes with its own API for loading components dynamically. In the following sections you will learn how to use it. + + +## Where to load the component + +Before components can be added we have to define an anchor point to mark where components can be inserted dynamically. + +The ad banner uses a helper directive called `AdDirective` to mark valid insertion points in the template. + + +{@example 'cb-dynamic-component-loader/ts/src/app/ad.directive.ts'} + +`AdDirective` injects `ViewContainerRef` to gain access to the view container of the element that will become the host of the dynamically added component. + +## Loading components + +The next step is to implement the ad banner. Most of the implementation is in `AdBannerComponent`. + +We start by adding a `template` element with the `AdDirective` directive applied. + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/ad.service.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/ad-item.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/app.module.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/app.component.ts'} + + + + + +The `template` element decorated with the `ad-host` directive marks where dynamically loaded components will be added. + +Using a `template` element is recommended since it doesn't render any additional output. + + +{@example 'cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts' region='ad-host'} + +### Resolving Components + +`AdBanner` takes an array of `AdItem` objects as input. `AdItem` objects specify the type of component to load and any data to bind to the component. + +The ad components making up the ad campaign are returned from `AdService`. + +Passing an array of components to `AdBannerComponent` allows for a dynamic list of ads without static elements in the template. + +`AdBannerComponent` cycles through the array of `AdItems` and loads the corresponding components on an interval. Every 3 seconds a new component is loaded. + +`ComponentFactoryResolver` is used to resolve a `ComponentFactory` for each specific component. The component factory is need to create an instance of the component. + +`ComponentFactories` are generated by the Angular compiler. + +Generally the compiler will generate a component factory for any component referenced in a template. + +With dynamically loaded components there are no selector references in the templates since components are loaded at runtime. In order to ensure that the compiler will still generate a factory, dynamically loaded components have to be added to their `NgModule`'s `entryComponents` array. + + +{@example 'cb-dynamic-component-loader/ts/src/app/app.module.ts' region='entry-components'} + +Components are added to the template by calling `createComponent` on the `ViewContainerRef` reference. + +`createComponent` returns a reference to the loaded component. The component reference can be used to pass input data or call methods to interact with the component. + +In the Ad banner, all components implement a common `AdComponent` interface to standardize the api for passing data to the components. + +Two sample components and the `AdComponent` interface are shown below: + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/hero-profile.component.ts'} + + + + + {@example 'cb-dynamic-component-loader/ts/src/app/ad.component.ts'} + + + + + +The final ad banner looks like this: +
+ Ads +
+ diff --git a/aio/content/cookbook/dynamic-form.md b/aio/content/cookbook/dynamic-form.md new file mode 100644 index 0000000000..a66e732e85 --- /dev/null +++ b/aio/content/cookbook/dynamic-form.md @@ -0,0 +1,168 @@ +@title +Dynamic Forms + +@intro +Render dynamic forms with FormGroup + +@description +We can't always justify the cost and time to build handcrafted forms, +especially if we'll need a great number of them, they're similar to each other, and they change frequently +to meet rapidly changing business and regulatory requirements. + +It may be more economical to create the forms dynamically, based on metadata that describe the business object model. + +In this cookbook we show how to use `formGroup` to dynamically render a simple form with different control types and validation. +It's a primitive start. +It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience. +All such greatness has humble beginnings. + +In our example we use a dynamic form to build an online application experience for heroes seeking employment. +The agency is constantly tinkering with the application process. +We can create the forms on the fly *without changing our application code*. +## Table of contents + + [Bootstrap](#bootstrap) + + [Question Model](#object-model) + + [Form Component](#form-component) + + [Questionnaire Metadata](#questionnaire-metadata) + + [Dynamic Template](#dynamic-template) +**See the **. + +## Bootstrap + +We start by creating an `NgModule` called `AppModule`. + +In our example we will be using Reactive Forms. + +Reactive Forms belongs to a different `NgModule` called `ReactiveFormsModule`, so in order to access any Reactive Forms directives, we have to import `ReactiveFormsModule` from the `@angular/forms` library. + +We bootstrap our `AppModule` in main.ts. + + + + + {@example 'cb-dynamic-form/ts/src/app/app.module.ts'} + + + + + {@example 'cb-dynamic-form/ts/src/main.ts'} + + + + + + +## Question Model + +The next step is to define an object model that can describe all scenarios needed by the form functionality. +The hero application process involves a form with a lot of questions. +The "question" is the most fundamental object in the model. + +We have created `QuestionBase` as the most fundamental question class. + + +{@example 'cb-dynamic-form/ts/src/app/question-base.ts'} + +From this base we derived two new classes in `TextboxQuestion` and `DropdownQuestion` that represent Textbox and Dropdown questions. +The idea is that the form will be bound to specific question types and render the appropriate controls dynamically. + +`TextboxQuestion` supports multiple html5 types like text, email, url etc via the `type` property. + + +{@example 'cb-dynamic-form/ts/src/app/question-textbox.ts'} + +`DropdownQuestion` presents a list of choices in a select box. + + +{@example 'cb-dynamic-form/ts/src/app/question-dropdown.ts'} + +Next we have defined `QuestionControlService`, a simple service for transforming our questions to a `FormGroup`. +In a nutshell, the form group consumes the metadata from the question model and allows us to specify default values and validation rules. + + +{@example 'cb-dynamic-form/ts/src/app/question-control.service.ts'} + +## Question form components +Now that we have defined the complete model we are ready to create components to represent the dynamic form. +`DynamicFormComponent` is the entry point and the main container for the form. + + + + {@example 'cb-dynamic-form/ts/src/app/dynamic-form.component.html'} + + + + + {@example 'cb-dynamic-form/ts/src/app/dynamic-form.component.ts'} + + + + + +It presents a list of questions, each question bound to a `` component element. +The `` tag matches the `DynamicFormQuestionComponent`, +the component responsible for rendering the details of each _individual_ question based on values in the data-bound question object. + + + + + {@example 'cb-dynamic-form/ts/src/app/dynamic-form-question.component.html'} + + + + + {@example 'cb-dynamic-form/ts/src/app/dynamic-form-question.component.ts'} + + + + + +Notice this component can present any type of question in our model. +We only have two types of questions at this point but we can imagine many more. +The `ngSwitch` determines which type of question to display. + +In both components we're relying on Angular's **formGroup** to connect the template HTML to the +underlying control objects, populated from the question model with display and validation rules. + +`formControlName` and `formGroup` are directives defined in `ReactiveFormsModule`. Our templates can can access these directives directly since we imported `ReactiveFormsModule` from `AppModule`. +## Questionnaire data`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`. + + The set of questions we have defined for the job application is returned from the `QuestionService`. + In a real app we'd retrieve these questions from storage. + + The key point is that we control the hero job application questions entirely through the objects returned from `QuestionService`. + Questionnaire maintenance is a simple matter of adding, updating, and removing objects from the `questions` array. + + +{@example 'cb-dynamic-form/ts/src/app/question.service.ts'} + +Finally, we display an instance of the form in the `AppComponent` shell. + + +{@example 'cb-dynamic-form/ts/src/app/app.component.ts'} + +## Dynamic Template +Although in this example we're modelling a job application for heroes, there are no references to any specific hero question +outside the objects returned by `QuestionService`. + +This is very important since it allows us to repurpose the components for any type of survey +as long as it's compatible with our *question* object model. +The key is the dynamic data binding of metadata used to render the form +without making any hardcoded assumptions about specific questions. +In addition to control metadata, we are also adding validation dynamically. + +The *Save* button is disabled until the form is in a valid state. +When the form is valid, we can click *Save* and the app renders the current form values as JSON. +This proves that any user input is bound back to the data model. +Saving and retrieving the data is an exercise for another time. +The final form looks like this: +
+ Dynamic-Form +
+ +[Back to top](#top) \ No newline at end of file diff --git a/aio/content/cookbook/form-validation.md b/aio/content/cookbook/form-validation.md new file mode 100644 index 0000000000..2fdb7559e7 --- /dev/null +++ b/aio/content/cookbook/form-validation.md @@ -0,0 +1,486 @@ +@title +Form Validation + +@intro +Validate user's form entries + +@description + + +{@a top} +We can improve overall data quality by validating user input for accuracy and completeness. + +In this cookbook we show how to validate user input in the UI and display useful validation messages +using first the template-driven forms and then the reactive forms approach. +Learn more about these choices in the [Forms chapter.](../guide/forms.html) + + +{@a toc} +## Table of Contents + + [Simple Template-Driven Forms](#template1) + + [Template-Driven Forms with validation messages in code](#template2) + + [Reactive Forms with validation in code](#reactive) + + [Custom validation](#custom-validation) + + [Testing](#testing) + + +{@a live-example} +**Try the live example to see and download the full cookbook source code** + + + + + + + +{@a template1} +## Simple Template-Driven Forms + +In the template-driven approach, you arrange +[form elements](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms_in_HTML) in the component's template. + +You add Angular form directives (mostly directives beginning `ng...`) to help +Angular construct a corresponding internal control model that implements form functionality. +We say that the control model is _implicit_ in the template. + +To validate user input, you add [HTML validation attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) +to the elements. Angular interprets those as well, adding validator functions to the control model. + +Angular exposes information about the state of the controls including +whether the user has "touched" the control or made changes and if the control values are valid. + +In the first template validation example, +we add more HTML to read that control state and update the display appropriately. +Here's an excerpt from the template html for a single input box control bound to the hero name: + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.html' region='name-with-error-msg'} + +Note the following: +- The `` element carries the HTML validation attributes: `required`, `minlength`, and `maxlength`. + +- We set the `name` attribute of the input box to `"name"` so Angular can track this input element and associate it +with an Angular form control called `name` in its internal control model. + +- We use the `[(ngModel)]` directive to two-way data bind the input box to the `hero.name` property. + +- We set a template variable (`#name`) to the value `"ngModel"` (always `ngModel`). +This gives us a reference to the Angular `NgModel` directive +associated with this control that we can use _in the template_ +to check for control states such as `valid` and `dirty`. + +- The `*ngIf` on `
` element reveals a set of nested message `divs` but only if there are "name" errors and +the control is either `dirty` or `touched`. + +- Each nested `
` can present a custom message for one of the possible validation errors. +We've prepared messages for `required`, `minlength`, and `maxlength`. + +The full template repeats this kind of layout for each data entry control on the form. +#### Why check _dirty_ and _touched_? + +We shouldn't show errors for a new hero before the user has had a chance to edit the value. +The checks for `dirty` and `touched` prevent premature display of errors. + +Learn about `dirty` and `touched` in the [Forms](../guide/forms.html) chapter.The component class manages the hero model used in the data binding +as well as other code to support the view. + + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.ts' region='class'} + +Use this template-driven validation technique when working with static forms with simple, standard validation rules. + +Here are the complete files for the first version of `HeroFormTemplateCompononent` in the template-driven approach: + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.html'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.ts'} + + + + + + + + +{@a template2} +## Template-Driven Forms with validation messages in code + +While the layout is straightforward, +there are obvious shortcomings with the way we handle validation messages: + +* It takes a lot of HTML to represent all possible error conditions. +This gets out of hand when there are many controls and many validation rules. + +* We're not fond of so much JavaScript logic in HTML. + +* The messages are static strings, hard-coded into the template. +We often require dynamic messages that we should shape in code. + +We can move the logic and the messages into the component with a few changes to +the template and component. + +Here's the hero name again, excerpted from the revised template ("Template 2"), next to the original version: + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.html' region='name-with-error-msg'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.html' region='name-with-error-msg'} + + + + + +The `` element HTML is almost the same. There are noteworthy differences: +- The hard-code error message `` are gone. + +- There's a new attribute, `forbiddenName`, that is actually a custom validation directive. +It invalidates the control if the user enters "bob" anywhere in the name ([try it](#live-example)). +We discuss [custom validation directives](#custom-validation) later in this cookbook. + +- The `#name` template variable is gone because we no longer refer to the Angular control for this element. + +- Binding to the new `formErrors.name` property is sufficent to display all name validation error messages. + +#### Component class +The original component code stays the same. +We _added_ new code to acquire the Angular form control and compose error messages. + +The first step is to acquire the form control that Angular created from the template by querying for it. + +Look back at the top of the component template where we set the +`#heroForm` template variable in the `
` element: + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.html' region='form-tag'} + +The `heroForm` variable is a reference to the control model that Angular derived from the template. +We tell Angular to inject that model into the component class's `currentForm` property using a `@ViewChild` query: + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.ts' region='view-child'} + +Some observations: + +- Angular `@ViewChild` queries for a template variable when you pass it +the name of that variable as a string (`'heroForm'` in this case). + +- The `heroForm` object changes several times during the life of the component, most notably when we add a new hero. +We'll have to re-inspect it periodically. + +- Angular calls the `ngAfterViewChecked` [lifecycle hook method](../guide/lifecycle-hooks.html#afterview) +when anything changes in the view. +That's the right time to see if there's a new `heroForm` object. + +- When there _is_ a new `heroForm` model, we subscribe to its `valueChanged` _Observable_ property. +The `onValueChanged` handler looks for validation errors after every user keystroke. + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.ts' region='handler'} + +The `onValueChanged` handler interprets user data entry. +The `data` object passed into the handler contains the current element values. +The handler ignores them. Instead, it iterates over the fields of the component's `formErrors` object. + +The `formErrors` is a dictionary of the hero fields that have validation rules and their current error messages. +Only two hero properties have validation rules, `name` and `power`. +The messages are empty strings when the hero data are valid. + +For each field, the handler + - clears the prior error message if any + - acquires the field's corresponding Angular form control + - if such a control exists _and_ its been changed ("dirty") _and_ its invalid ... + - the handler composes a consolidated error message for all of the control's errors. + +We'll need some error messages of course, a set for each validated property, one message per validation rule: + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.ts' region='messages'} + +Now every time the user makes a change, the `onValueChanged` handler checks for validation errors and produces messages accordingly. + +### Is this an improvement? + +Clearly the template got substantially smaller while the component code got substantially larger. +It's not easy to see the benefit when there are just three fields and only two of them have validation rules. + +Consider what happens as we increase the number of validated fields and rules. +In general, HTML is harder to read and maintain than code. +The initial template was already large and threatening to get rapidly worse as we add more validation message ``. + +After moving the validation messaging to the component, +the template grows more slowly and proportionally. +Each field has approximately the same number of lines no matter its number of validation rules. +The component also grows proportionally, at the rate of one line per validated field +and one line per validation message. + +Both trends are manageable. + +Now that the messages are in code, we have more flexibility. We can compose messages more intelligently. +We can refactor the messages out of the component, perhaps to a service class that retrieves them from the server. +In short, there are more opportunities to improve message handling now that text and logic have moved from template to code. + +### _FormModule_ and template-driven forms + +Angular has two different forms modules — `FormsModule` and `ReactiveFormsModule` — +that correspond with the two approaches to form development. +Both modules come from the same `@angular/forms` library package. + +We've been reviewing the "Template-driven" approach which requires the `FormsModule` +Here's how we imported it in the `HeroFormTemplateModule`. + + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template.module.ts'} + + +We haven't talked about the `SharedModule` or its `SubmittedComponent` which appears at the bottom of every +form template in this cookbook. + +They're not germane to the validation story. Look at the [live example](#live-example) if you're interested. + + + +{@a reactive} +## Reactive Forms + +In the template-driven approach, you markup the template with form elements, validation attributes, +and `ng...` directives from the Angular `FormsModule`. +At runtime, Angular interprets the template and derives its _form control model_. + +**Reactive Forms** takes a different approach. +You create the form control model in code. You write the template with form elements +and`form...` directives from the Angular `ReactiveFormsModule`. +At runtime, Angular binds the template elements to your control model based on your instructions. + +This approach requires a bit more effort. *You have to write the control model and manage it*. + +In return, you can +* add, change, and remove validation functions on the fly +* manipulate the control model dynamically from within the component +* [test](#testing) validation and control logic with isolated unit tests. + +The third cookbook sample re-writes the hero form in _reactive forms_ style. + +### Switch to the _ReactiveFormsModule_ +The reactive forms classes and directives come from the Angular `ReactiveFormsModule`, not the `FormsModule`. +The application module for the "Reactive Forms" feature in this sample looks like this: + +{@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.module.ts'} + +The "Reactive Forms" feature module and component are in the `src/app/reactive` folder. +Let's focus on the `HeroFormReactiveComponent` there, starting with its template. + +### Component template + +We begin by changing the `` tag so that it binds the Angular `formGroup` directive in the template +to the `heroForm` property in the component class. +The `heroForm` is the control model that the component class builds and maintains. + + +{@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.html' region='form-tag'} + +Then we modify the template HTML elements to match the _reactive forms_ style. +Here is the "name" portion of the template again, revised for reactive forms and compared with the template-driven version: + + + + {@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.html' region='name-with-error-msg'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.html' region='name-with-error-msg'} + + + + + +Key changes: +- the validation attributes are gone (except `required`) because we'll be validating in code. + +- `required` remains, not for validation purposes (we'll cover that in the code), +but rather for css styling and accessibility. + +A future version of reactive forms will add the `required` HTML validation attribute to the DOM element +(and perhaps the `aria-required` attribute) when the control has the `required` validator function. + +Until then, apply the `required` attribute _and_ add the `Validator.required` function +to the control model, as we'll do below. +- the `formControlName` replaces the `name` attribute; it serves the same +purpose of correlating the input box with the Angular form control. + +- the two-way `[(ngModel)]` binding is gone. +The reactive approach does not use data binding to move data into and out of the form controls. +We do that in code. + +The retreat from data binding is a principle of the reactive paradigm rather than a technical limitation.### Component class + +The component class is now responsible for defining and managing the form control model. + +Angular no longer derives the control model from the template so we can no longer query for it. +We create the Angular form control model explicitly with the help of the `FormBuilder`. + +Here's the section of code devoted to that process, paired with the template-driven code it replaces: + + + + {@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts' region='form-builder'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.ts' region='view-child'} + + + + + +- we inject the `FormBuilder` in a constructor. + +- we call a `buildForm` method in the `ngOnInit` [lifecycle hook method](../guide/lifecycle-hooks.html#hooks-overview) +because that's when we'll have the hero data. We'll call it again in the `addHero` method. +A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook.- the `buildForm` method uses the `FormBuilder` (`fb`) to declare the form control model. +Then it attaches the same `onValueChanged` handler (there's a one line difference) +to the form's `valueChanged` event and calls it immediately +to set error messages for the new control model. +#### _FormBuilder_ declaration +The `FormBuilder` declaration object specifies the three controls of the sample's hero form. + +Each control spec is a control name with an array value. +The first array element is the current value of the corresponding hero field. +The (optional) second value is a validator function or an array of validator functions. + +Most of the validator functions are stock validators provided by Angular as static methods of the `Validators` class. +Angular has stock validators that correspond to the standard HTML validation attributes. + +The `forbiddenNames` validator on the `"name"` control is a custom validator, +discussed in a separate [section below](#custom-validation). + + Learn more about `FormBuilder` in a _forthcoming_ chapter on reactive forms. +#### Committing hero value changes + +In two-way data binding, the user's changes flow automatically from the controls back to the data model properties. +Reactive forms do not use data binding to update data model properties. +The developer decides _when and how_ to update the data model from control values. + +This sample updates the model twice: +1. when the user submits the form +1. when the user chooses to add a new hero + +The `onSubmit` method simply replaces the `hero` object with the combined values of the form: + +{@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts' region='on-submit'} + + +This example is "lucky" in that the `heroForm.value` properties _just happen_ to +correspond _exactly_ to the hero data object properties.The `addHero` method discards pending changes and creates a brand new `hero` model object. + +{@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts' region='add-hero'} + +Then it calls `buildForm` again which replaces the previous `heroForm` control model with a new one. +The `` tag's `[formGroup]` binding refreshes the page with the new control model. + +Here's the complete reactive component file, compared to the two template-driven component files. + + + + {@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.ts'} + + + + + {@example 'cb-form-validation/ts/src/app/template/hero-form-template1.component.ts'} + + + + + + +Run the [live example](#live-example) to see how the reactive form behaves +and to compare all of the files in this cookbook sample. + + + +{@a custom-validation} +## Custom validation +This cookbook sample has a custom `forbiddenNamevalidator` function that's applied to both the +template-driven and the reactive form controls. It's in the `src/app/shared` folder +and declared in the `SharedModule`. + +Here's the `forbiddenNamevalidator` function itself: + +{@example 'cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts' region='custom-validator'} + +The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name +and returns a validator function. + +In this sample, the forbidden name is "bob"; +the validator rejects any hero name containing "bob". +Elsewhere it could reject "alice" or any name that the configuring regular expression matches. + +The `forbiddenNamevalidator` factory returns the configured validator function. +That function takes an Angular control object and returns _either_ +null if the control value is valid _or_ a validation error object. +The validation error object typically has a property whose name is the validation key ('forbiddenName') +and whose value is an arbitrary dictionary of values that we could insert into an error message (`{name}`). + +Learn more about validator functions in a _forthcoming_ chapter on custom form validation.#### Custom validation directive +In the reactive forms component we added a configured `forbiddenNamevalidator` +to the bottom of the `'name'` control's validator function list. + +{@example 'cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts' region='name-validators'} + +In the template-driven component template, we add the selector (`forbiddenName`) of a custom _attribute directive_ to the name's input box +and configured it to reject "bob". + +{@example 'cb-form-validation/ts/src/app/template/hero-form-template2.component.html' region='name-input'} + +The corresponding `ForbiddenValidatorDirective` is a wrapper around the `forbiddenNamevalidator`. + +Angular forms recognizes the directive's role in the validation process because the directive registers itself +with the `NG_VALIDATORS` provider, a provider with an extensible collection of validation directives. + +{@example 'cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts' region='directive-providers'} + +The rest of the directive is unremarkable and we present it here without further comment. + +{@example 'cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts' region='directive'} + + +See the [Attribute Directives](../guide/attribute-directives.html) chapter. + + + +{@a testing} +## Testing Considerations + +We can write _isolated unit tests_ of validation and control logic in _Reactive Forms_. + +_Isolated unit tests_ probe the component class directly, independent of its +interactions with its template, the DOM, other dependencies, or Angular itself. + +Such tests have minimal setup, are quick to write, and easy to maintain. +They do not require the `Angular TestBed` or asynchronous testing practices. + +That's not possible with _Template-driven_ forms. +The template-driven approach relies on Angular to produce the control model and +to derive validation rules from the HTML validation attributes. +You must use the `Angular TestBed` to create component test instances, +write asynchronous tests, and interact with the DOM. + +While not difficult, this takes more time, work and skill — +factors that tend to diminish test code coverage and quality. \ No newline at end of file diff --git a/aio/content/cookbook/i18n.md b/aio/content/cookbook/i18n.md new file mode 100644 index 0000000000..851a889093 --- /dev/null +++ b/aio/content/cookbook/i18n.md @@ -0,0 +1,620 @@ +@title +Internationalization (i18n) + +@intro +Translate the app's template text into multiple languages. + +@description + + +{@a top} +Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages. + +## Table of contents + + * [Angular and i18n template translation](#angular-i18n) + * [Mark text with the _i18n_ attribute](#i18n-attribute) + * [Add _i18n-..._ translation attributes](#translate-attributes) + * [Handle singular and plural](#cardinality) + * [Select among alternative texts](#select) + * [Create a translation source file with the **_ng-xi18n_ extraction tool**](#ng-xi18n) + * [Translate text messages](#translate) + * [Merge the completed translation file into the app](#merge) + * [Merge with the JIT compiler](#jit) + * [Internationalization with the AOT compiler](#aot) + * [Translation file maintenance and _id_ changes](#maintenance) +**Try this** live example +of a JIT-compiled app, translated into Spanish. + + + +{@a angular-i18n} + +## Angular and _i18n_ template translation + +Application internationalization is a challenging, many-faceted effort that +takes dedication and enduring commitment. +Angular's _i18n_ internationalization facilities can help. + +This page describes the _i18n_ tools available to assist translation of component template text +into multiple languages. + + +Practitioners of _internationalization_ refer to a translatable text as a "_message_". +This page uses the words "_text_" and "_message_" interchangably and in the combination, "_text message_". +The _i18n_ template translation process has four phases: + +1. Mark static text messages in your component templates for translation. + +1. An angular _i18n_ tool extracts the marked messages into an industry standard translation source file. + +1. A translator edits that file, translating the extracted text messages into the target language, +and returns the file to you. + +1. The Angular compiler imports the completed translation files, +replaces the original messages with translated text, and generates a new version of the application +in the target language. + +You need to build and deploy a separate version of the application for each supported language. + + +{@a i18n-attribute} + +## Mark text with the _i18n_ attribute + +The Angular `i18n` attribute is a marker for translatable content. +Place it on every element tag whose fixed text should be translated. + + +~~~ {.alert.is-helpful} + +`i18n` is not an Angular _directive_. +It's a custom _attribute_, recognized by Angular tools and compilers. +After translation, the compiler removes it. + + +~~~ + +In the accompanying sample, an `

` tag displays a simple English language greeting +that you translate into Spanish: + +{@example 'cb-i18n/ts/src/app/app.component.1.html' region='greeting'} + +Add the `i18n` attribute to the tag to mark it for translation. + + +{@example 'cb-i18n/ts/src/app/app.component.1.html' region='i18n-attribute'} + +### Help the translator with a _description_ and _intent_ + +In order to translate it accurately, the translator may +need a description of the message. +Assign a description to the i18n attribute: + + +{@example 'cb-i18n/ts/src/app/app.component.1.html' region='i18n-attribute-desc'} + +In order to deliver a correct translation, the translator may need to +know your _intent_—the true _meaning_ of the text +within _this particular_ application context. +In front of the description, add some contextual meaning to the assigned string, +separating it from the description with the `|` character (`|`): + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-attribute-meaning'} + +While all appearances of a message with the _same_ meaning have the _same_ translation, +a message with *a variety of possible meanings* could have different translations. +The Angular extraction tool preserves both the _meaning_ and the _description_ in the translation source file +to facilitiate contextually-specific translations. + +### Translate text without creating an element + +Suppose there is a stretch of text that you'd like to translate. +You could wrap it in a `` tag but for some reason (CSS comes to mind) +you don't want to create a new DOM element merely to facilitate translation. + +Here are two techniques to try. + +(1) Wrap the text in an `` element. The `` is never renderered: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-ng-container'} + +(2) Wrap the text in a pair of HTML comments: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-with-comment'} + + + + +{@a translate-attributes} +## Add _i18n-..._ translation attributes +You've added an image to your template. You care about accessibility too so you add a `title` attribute: + + +{@example 'cb-i18n/ts/src/app/app.component.1.html' region='i18n-title'} + +The `title` attribute needs to be translated. +Angular i18n support has more translation attributes in the form,`i18n-x`, where `x` is the +name of the attribute to translate. + +To translate the `title` on the `img` tag from the previous example, write: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-title-translate'} + +You can also assign a meaning and a description with the `i18n-x="|"` syntax. + + + +{@a cardinality} +## Handle singular and plural + +Different languages have different pluralization rules. + +Suppose your application says something about a collection of wolves. +In English, depending upon the number of wolves, you could display "no wolves", "one wolf", "two wolves", or "a wolf pack". +Other languages might express the _cardinality_ differently. + +Here's how you could mark up the component template to display the phrase appropriate to the number of wolves: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-plural'} + +* The first parameter is the key. It is bound to the component property (`wolves`) +that determines the number of wolves. +* The second parameter identifies this as a `plural` translation type. +* The third parameter defines a pluralization pattern consisting of pluralization +categories and their matching values. + +Pluralization categories include: +* =0 +* =1 +* =5 +* few +* other + +Put the default _English_ translation in braces (`{}`) next to the pluralization category. +* When you're talking about one wolf, you could write `=1 {one wolf}`. +* For zero wolves, you could write `=0 {no wolves}`. +* For two wolves, you could write `=2 {two wolves}`. + +You could keep this up for three, four, and every other number of wolves. +Or you could specify the **`other`** category as a catch-all for any unmatched cardinality +and write something like: `other {a wolf pack}`. + +This syntax conforms to the +ICU Message Format +that derives from the +Common Locale Data Repository (CLDR), +which specifies the +pluralization rules. + + +{@a select} +## Select among alternative texts +The application displays different text depending upon whether the hero is male or female. +These text alternatives require translation too. + +You can handle this with a `select` translation. +A `select` also follows the +ICU message syntax. +You choose among alternative translation based on a string value instead of a number. + +The following format message in the component template binds to the component's `gender` +property, which outputs either an "m" or an "f". +The message maps those values to the appropriate translation: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-select'} + + + +{@a ng-xi18n} + +## Create a translation source file with the _ng-xi18n_ tool + +Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts +into a translation source file in an industry standard format. + +This is an Angular CLI tool in the `@angular/compiler-cli` npm package. +If you haven't already installed the CLI and its `platform-server` peer dependency, do so now: + + + npm install @angular/compiler-cli @angular/platform-server --save + + + +Open a terminal window at the root of the application project and enter the `ng-xi18n` command: + + + ./node_modules/.bin/ng-xi18n + + + + +Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"` +By default, the tool generates a translation file named **`messages.xlf`** in the +XML Localisation Interchange File Format (XLIFF, version 1.2). + + +{@a other-formats} +### Other translation formats + +You can generate a file named **`messages.xmb`** in the +XML Message Bundle (XMB) format +by adding the `--i18nFormat=xmb` flag. + + + ./node_modules/.bin/ng-xi18n --i18nFormat=xmb + + + +This sample sticks with the _XLIFF_ format. + + +{@a ng-xi18n-options} +### Other options +You may have to specify additional options. +For example, if the `tsconfig.json` TypeScript configuration +file is located somewhere other than in the root folder, +you must identify the path to it with the `-p` option: + + ./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json + ./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p path/to/tsconfig.json + + + + + + +{@a npm-i18n-script} +### Add an _npm_ script for convenience + +Consider adding a convenience shortcut to the `scripts` section of the `package.json` +to make the command easier to remember and run: + + "scripts": { + "i18n": "ng-xi18n", + ... + } + + +Now you can issue command variations such as these: + + npm run i18n + npm run i18n -- -p path/to/tsconfig.json + npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json + + +Note the `--` flag before the options. +It tells _npm_ to pass every flag thereafter to `ng-xi18n`. + + +{@a translate} + +## Translate text messages + +The `ng-xi18n` command generates a translation source file +in the project root folder named `messages.xlf`. +The next step is to translate the English language template +text into the specific language translation +files. The cookbook sample creates a Spanish translation file. + + +{@a localization-folder} +### Create a localization folder + +You will probably translate into more than one other language so it's a good idea +for the project structure to reflect your entire internationalization effort. + +One approach is to dedicate a folder to localization and store related assets +(for example, internationalization files) there. +Localization and internationalization are +different but closely related terms.This cookbook follows that suggestion. It has a `locale` folder under the `src/`. +Assets within the folder carry a filename extension that matches a language-culture code from a +well-known codeset. + +Make a copy of the `messages.xlf` file, put it in the `locale` folder and +rename it `messages.es.xlf`for the Spanish language translation. +Do the same for each target language. + +### Translate text nodes +In the real world, you send the `messages.es.xlf` file to a Spanish translator who fills in the translations +using one of the +many XLIFF file editors. + +This sample file is easy to translate without a special editor or knowledge of Spanish. +Open `messages.es.xlf` and find the first `` section: + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translated-hello'} + +This XML element represents the translation of the `

` greeting tag you marked with the `i18n` attribute. + +Using the _source_, _description_, and _meaning_ elements to guide your translation, +replace the `` tag with the Spanish greeting: + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translated-hello'} + + + +~~~ {.alert.is-important} + +Note that the tool generates the `id`. **Don't touch it.** +Its value depends on the content of the message and its assigned meaning. +Change either factor and the `id` changes as well. +See the **[translation file maintenance discussion](#maintenance)**. + + +~~~ + +Translate the other text nodes the same way: + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translated-other-nodes'} + + + +{@a translate-plural-select} +## Translate _plural_ and _select_ +Translating _plural_ and _select_ messages is a little tricky. + +The `` tag is empty for `plural` and `select` translation +units, which makes them hard to correlate with the original template. +The `XLIFF` format doesn't yet support the ICU rules; it soon will. +However, the `XMB` format does support the ICU rules. + +You'll just have to look for them in relation to other translation units that you recognize from elsewhere in the source template. +In this example, you know the translation unit for the `select` must be just below the translation unit for the logo. +### Translate _plural_ +To translate a `plural`, translate its ICU format match values: + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translated-plural'} + +### Translate _select_ +The `select` behaves a little differently. Here again is the ICU format message in the component template: + + +{@example 'cb-i18n/ts/src/app/app.component.html' region='i18n-select'} + +The extraction tool broke that into _two_ translation units. + +The first unit contains the text that was _outside_ the `select`. +In place of the `select` is a placeholder, ``, that represents the `select` message. +Translate the text and leave the placeholder where it is. + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translate-select-1'} + +The second translation unit, immediately below the first one, contains the `select` message. Translate that. + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translate-select-2'} + +Here they are together, after translation: + + +{@example 'cb-i18n/ts/src/locale/messages.es.xlf.html' region='translated-select'} + + +
+ +
+ +The entire template translation is complete. It's +time to incorporate that translation into the application. + +
+ +
+ +### The app before translation + +When the previous steps finish, the sample app _and_ its translation file are as follows: + + + + + {@example 'cb-i18n/ts/src/app/app.component.html'} + + + + + {@example 'cb-i18n/ts/src/app/app.component.ts'} + + + + + {@example 'cb-i18n/ts/src/app/app.module.ts'} + + + + + {@example 'cb-i18n/ts/src/main.1.ts'} + + + + + {@example 'cb-i18n/ts/src/locale/messages.es.xlf.html'} + + + + + + + +{@a merge} + +## Merge the completed translation file into the app + +To merge the translated text into component templates, +compile the application with the completed translation file. +The process is the same whether the file is in `.xlf` format or +in another format (`.xlif` and `.xtb`) that Angular understands. + +You provide the Angular compiler with three new pieces of information: + * the translation file + * the translation file format + * the _Locale ID_ + (`es` or `en-US` for instance) + +_How_ you provide this information depends upon whether you compile with +the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler. + + * With [JIT](#jit), you provide the information at bootstrap time. + * With [AOT](#aot), you pass the information as `ngc` options. + + +{@a jit} + +### Merge with the JIT compiler + +The JIT compiler compiles the application in the browser as the application loads. +Translation with the JIT compiler is a dynamic process of: + +1. Determining the language version for the current user. +2. Importing the appropriate language translation file as a string constant. +3. Creating corresponding translation providers to guide the JIT compiler. +4. Bootstrapping the application with those providers. + +Open `index.html` and revise the launch script as follows: + +{@example 'cb-i18n/ts/src/index.html' region='i18n'} + +In this sample, the user's language is hardcoded as a global `document.locale` variable +in the `index.html`. + + +{@a text-plugin} +### SystemJS Text plugin + +Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`. +With the help of a text plugin, SystemJS can read any file as raw text and +return the contents as a string. +You'll need it to import the language translation file. + +SystemJS doesn't ship with a raw text plugin but it's easy to add. +Create the following `systemjs-text-plugin.js` in the `src/` folder: + +{@example 'cb-i18n/ts/src/systemjs-text-plugin.js'} + +### Create translation providers + +Three providers tell the JIT compiler how to translate the template texts for a particular language +while compiling the application: + +* `TRANSLATIONS` is a string containing the content of the translation file. +* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb`. +* `LOCALE_ID` is the locale of the target language. + +The `getTranslationProviders` function in the following `src/app/i18n-providers.ts` +creates those providers based on the user's _locale_ +and the corresponding translation file: + +{@example 'cb-i18n/ts/src/app/i18n-providers.ts'} + +1. It gets the locale from the global `document.locale` variable that was set in `index.html`. + +1. If there is no locale or the language is U.S. English (`en-US`), there is no need to translate. + The function returns an empty `noProviders` array as a `Promise`. + It must return a `Promise` because this function could read a translation file asynchronously from the server. + +1. It creates a transaction filename from the locale according to the name and location convention +[described earlier](#localization-folder). + +1. The `getTranslationsWithSystemJs` method reads the translation and returns the contents as a string. +Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](#text-plugin). + +1. The callback composes a providers array with the three translation providers. + +1. Finally, `getTranslationProviders` returns the entire effort as a promise. + +### Bootstrap the app with translation providers + +The Angular `bootstrapModule` method has a second, _options_ parameter +that can influence the behavior of the compiler. + +You'll create an _options_ object with the translation providers from `getTranslationProviders` +and pass it to `bootstrapModule`. +Open the `src/main.ts` and modify the bootstrap code as follows: + +{@example 'cb-i18n/ts/src/main.ts'} + +Notice that it waits for the `getTranslationProviders` promise to resolve before +bootstrapping the app. + +The app is now _internationalized_ for English and Spanish and there is a clear path for adding +more languages. + + +{@a aot} + +### _Internationalize_ with the AOT compiler + +The JIT compiler translates the application into the target language +while compiling dynamically in the browser. +That's flexible but may not be fast enough for your users. + +The AOT (_Ahead-of-Time_) compiler is part of a build process that +produces a small, fast, ready-to-run application package. +When you internationalize with the AOT compiler, you pre-build +a separate application package for each +language. Then in the host web page (`index.html`), +you determine which language the user needs +and serve the appropriate application package. + +This cookbook doesn't cover how to build multiple application packages and +serve them according to the user's language preference. +It does explain the few steps necessary to tell the AOT compiler to apply a translations file. + +Internationalization with the AOT compiler requires +some setup specifically for AOT compilation. +Start with the application project as shown +[just before merging the translation file](#app-pre-translation) +and refer to the [AOT cookbook](aot-compiler.html) to make it _AOT-ready_. + +Next, issue an `ngc` compile command for each supported language (including English). +The result is a separate version of the application for each language. + +Tell AOT how to translate by adding three options to the `ngc` command: + * `--i18nFile`: the path to the translation file + * `--locale`: the name of the locale + * `--i18nFormat`: the format of the localization file + +For this sample, the Spanish language command would be + + ./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf + + + + +Windows users may have to quote the command: + + "./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf + + + + + +{@a maintenance} +## Translation file maintenance and _id_ changes + +As the application evolves, you will change the _i18n_ markup +and re-run the `ng-xi18n` extraction tool many times. +The _new_ markup that you add is not a problem; +but _most_ changes to _existing_ markup trigger +generation of _new_ `id`s for the affected translation units. + +After an `id` changes, the translation files are no longer in-sync. +**All translated versions of the application will fail** during re-compilation. +The error messages identify the old `id`s that are no longer valid but +they don't tell you what the new `id`s should be. + +**Commit all translation message files to source control**, +especially the English source `messages.xlf`. +The difference between the old and the new `messages.xlf` file + help you find and update `id` changes across your translation files. \ No newline at end of file diff --git a/aio/content/cookbook/index.md b/aio/content/cookbook/index.md new file mode 100644 index 0000000000..14bdfd7309 --- /dev/null +++ b/aio/content/cookbook/index.md @@ -0,0 +1,28 @@ +@title +Cookbook + +@intro +A collection of recipes for common Angular application scenarios + +@description +The *Cookbook* offers answers to common implementation questions. + +Each cookbook chapter is a collection of recipes focused on a particular Angular feature or application challenge +such as data binding, cross-component interaction, and communicating with a remote server via HTTP. + +The cookbook is just getting started. Many more recipes are on the way. +Each cookbook chapter links to a live sample with every recipe included. + +Recipes are deliberately brief and code-centric. +Each recipe links to a chapter of the Developer Guide or the API Guide +where you can learn more about the purpose, context, and design choices behind the code snippets. + +## Feedback + +The cookbook is a perpetual *work-in-progress*. +We welcome feedback! Leave a comment by clicking the icon in upper right corner of the banner. + +Post *documentation* issues and pull requests on the +[angular.io](https://github.com/angular/angular.io) github repository. + +Post issues with *Angular itself* to the [angular](https://github.com/angular/angular) github repository. \ No newline at end of file diff --git a/aio/content/cookbook/set-document-title.md b/aio/content/cookbook/set-document-title.md new file mode 100644 index 0000000000..8ee9fb536d --- /dev/null +++ b/aio/content/cookbook/set-document-title.md @@ -0,0 +1,103 @@ +@title +Set the Document Title + +@intro +Setting the document or window title using the Title service. + +@description + + +{@a top} +Our app should be able to make the browser title bar say whatever we want it to say. +This cookbook explains how to do it.**See the **. + + + + + + + + + + + + + + +
+ To see the browser title bar change in the live example, + open it again in the Plunker editor by clicking the icon in the upper right, + then pop out the preview window by clicking the blue 'X' button in the upper right corner. + + pop out the window

pop out the window +
+ +## The problem with *<title>* + +The obvious approach is to bind a property of the component to the HTML `` like this: +<code-example format=''> + <title>{{This_Does_Not_Work}}</title> +</code-example> + +Sorry but that won't work. +The root component of our application is an element contained within the `<body>` tag. +The HTML `<title>` is in the document `<head>`, outside the body, making it inaccessible to Angular data binding. + +We could grab the browser `document` object and set the title manually. +That's dirty and undermines our chances of running the app outside of a browser someday. +Running your app outside a browser means that you can take advantage of server-side +pre-rendering for near-instant first app render times and for SEO. It means you could run from +inside a Web Worker to improve your app's responsiveness by using multiple threads. And it +means that you could run your app inside Electron.js or Windows Universal to deliver it to the desktop. +## Use the *Title* service +Fortunately, Angular bridges the gap by providing a `Title` service as part of the *Browser platform*. +The [Title](../api/platform-browser/index/Title-class.html) service is a simple class that provides an API +for getting and setting the current HTML document title: + +* `getTitle() : string` — Gets the title of the current HTML document. +* `setTitle( newTitle : string )` — Sets the title of the current HTML document. + +Let's inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it: + + +{@example 'cb-set-document-title/ts/src/app/app.component.ts' region='class'} + +We bind that method to three anchor tags and, voilà! +<figure class='image-display'> + <img src="/resources/images/cookbooks/set-document-title/set-title-anim.gif" alt="Set title"> </img> +</figure> + +Here's the complete solution + +<md-tab-group> + + <md-tab label="src/main.ts"> + {@example 'cb-set-document-title/ts/src/main.ts'} + </md-tab> + + + <md-tab label="src/app/app.module.ts"> + {@example 'cb-set-document-title/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="src/app/app.component.ts"> + {@example 'cb-set-document-title/ts/src/app/app.component.ts'} + </md-tab> + + +</md-tab-group> + + +## Why we provide the *Title* service in *bootstrap* + +We generally recommended providing application-wide services in the root application component, `AppComponent`. + +Here we recommend registering the title service during bootstrapping, +a location we reserve for configuring the runtime Angular environment. + +That's exactly what we're doing. +The `Title` service is part of the Angular *browser platform*. +If we bootstrap our application into a different platform, +we'll have to provide a different `Title` service that understands the concept of a "document title" for that specific platform. +Ideally the application itself neither knows nor cares about the runtime environment.[Back to top](#top) \ No newline at end of file diff --git a/aio/content/cookbook/ts-to-js.md b/aio/content/cookbook/ts-to-js.md new file mode 100644 index 0000000000..4820e48f58 --- /dev/null +++ b/aio/content/cookbook/ts-to-js.md @@ -0,0 +1,868 @@ +@title +TypeScript to JavaScript + +@intro +Convert Angular TypeScript examples into ES6 and ES5 JavaScript + +@description +Anything you can do with Angular in _TypeScript_, you can also do +in JavaScript. Translating from one language to the other is mostly a +matter of changing the way you organize your code and access Angular APIs. + +_TypeScript_ is a popular language option for Angular development. +Most code examples on the Internet as well as on this site are written in _TypeScript_. +This cookbook contains recipes for translating _TypeScript_ +code examples to _ES6_ and to _ES5_ so that JavaScript developers +can read and write Angular apps in their preferred dialect. + + +{@a toc} +## Table of contents + +[_TypeScript_ to _ES6_ to _ES5_](#from-ts)<br> +[Modularity: imports and exports](#modularity)<br> +[Classes and Class Metadata](#class-metadata)<br> +[_ES5_ DSL](#dsl)<br> +[Interfaces](#interfaces)<br> +[Input and Output Metadata](#io-decorators)<br> +[Dependency Injection](#dependency-injection)<br> +[Host Binding](#host-binding)<br> +[View and Child Decorators](#view-child-decorators)<br> +[AOT compilation in _TypeScript_ Only](#aot)<br> + +**Run and compare the live <live-example name="cb-ts-to-js">_TypeScript_</live-example> and <live-example name="cb-ts-to-js" lang="js">JavaScript</live-example> +code shown in this cookbook.** + + +{@a from-ts} + +## _TypeScript_ to _ES6_ to _ES5_ + +_TypeScript_ +<a href="https://www.typescriptlang.org" target="_blank" title='"TypeScript is a typed, superset of JavaScript"'>is a typed superset of _ES6 JavaScript_</a>. +  _ES6 JavaScript_ is a superset of _ES5 JavaScript_.   _ES5_ is the kind of JavaScript that runs natively in all modern browsers. +The transformation of _TypeScript_ code all the way down to _ES5_ code can be seen as "shedding" features. + +The downgrade progression is +* _TypeScript_ to _ES6-with-decorators_ +* _ES6-with-decorators_ to _ES6-without-decorators_ ("_plain ES6_") +* _ES6-without-decorators_ to _ES5_ + +When translating from _TypeScript_ to _ES6-with-decorators_, remove +[class property access modifiers](http://www.typescriptlang.org/docs/handbook/classes.html#public-private-and-protected-modifiers) +such as `public` and `private`. +Remove most of the +[type declarations](https://www.typescriptlang.org/docs/handbook/basic-types.html), +such as `:string` and `:boolean` +but **keep the constructor parameter types which are used for dependency injection**. + + +From _ES6-with-decorators_ to _plain ES6_, remove all +[decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) +and the remaining types. +You must declare properties in the class constructor (`this.title = '...'`) rather than in the body of the class. + +Finally, from _plain ES6_ to _ES5_, the main missing features are `import` +statements and `class` declarations. + +For _plain ES6_ transpilation you can _start_ with a setup similar to the +[_TypeScript_ quickstart](https://github.com/angular/quickstart) and adjust the application code accordingly. +Transpile with [Babel](https://babeljs.io/) using the `es2015` preset. +To use decorators and annotations with Babel, install the +[`angular2`](https://github.com/shuhei/babel-plugin-angular2-annotations) preset as well. + + + +{@a modularity} + +## Importing and Exporting + +### Importing Angular Code + +In both _TypeScript_ and _ES6_, you import Angular classes, functions, and other members with _ES6_ `import` statements. + +In _ES5_, you access the Angular entities of the [the Angular packages](../glossary.html#scoped-package) +through the global `ng` object. +Anything you can import from `@angular` is a nested member of this `ng` object: + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/app.module.ts' region='ng2import'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/app.module.es6' region='ng2import'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/app.module.es6' region='ng2import'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/app.module.js' region='ng2import'} + </md-tab> + + +</md-tab-group> + +### Exporting Application Code + +Each file in a _TypeScript_ or _ES6_ Angular application constitutes an _ES6_ module. +When you want to make something available to other modules, you `export` it. + +_ES5_ lacks native support for modules. +In an Angular _ES5_ application, you load each file manually by adding a `<script>` tag to `index.html`. + +~~~ {.alert.is-important} + +The order of `<script>` tags is often significant. +You must load a file that defines a public JavaScript entity before a file that references that entity. + +~~~ + +The best practice in _ES5_ is to create a form of modularity that avoids polluting the global scope. +Add one application namespace object such as `app` to the global `document`. +Then each code file "exports" public entities by attaching them to that namespace object, e.g., `app.HeroComponent`. +You could factor a large application into several sub-namespaces +which leads to "exports" along the lines of `app.heroQueries.HeroComponent`. + +Every _ES5_ file should wrap code in an +[Immediately Invoked Function Expression (IIFE)](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) +to limit unintentional leaking of private symbols into the global scope. + +Here is a `HeroComponent` as it might be defined and "exported" in each of the four language variants. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero.component.ts' region='appexport'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6' region='appexport'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero.component.es6' region='appexport'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero.component.js' region='appexport'} + </md-tab> + + +</md-tab-group> + +### Importing Application Code + +In _TypeScript_ and _ES6_ apps, you `import` things that have been exported from other modules. + +In _ES5_ you use the shared namespace object to access "exported" entities from other files. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/app.module.ts' region='appimport'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/app.module.es6' region='appimport'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/app.module.es6' region='appimport'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/app.module.js' region='appimport'} + </md-tab> + + +</md-tab-group> + + + +~~~ {.alert.is-helpful} + +Alternatively, you can use a module loader such as Webpack or +Browserify in an Angular JavaScript project. In such a project, you would +use _CommonJS_ modules and the `require` function to load Angular framework code. +Then use `module.exports` and `require` to export and import application code. + + + +~~~ + + + +{@a class-metadata} + +## Classes and Class Metadata + +### Classes + +Most Angular _TypeScript_ and _ES6_ code is written as classes. + +Properties and method parameters of _TypeScript_ classes may be marked with the access modifiers +`private`, `internal`, and `public`. +Remove these modifiers when translating to JavaScript. + +Most type declarations (e.g, `:string` and `:boolean`) should be removed when translating to JavaScript. +When translating to _ES6-with-decorators_, ***do not remove types from constructor parameters!*** + +Look for types in _TypeScript_ property declarations. +In general it is better to initialize such properties with default values because +many browser JavaScript engines can generate more performant code. +When _TypeScript_ code follows this same advice, it can infer the property types +and there is nothing to remove during translation. + +In _ES6-without-decorators_, properties of classes must be assigned inside the constructor. + +_ES5_ JavaScript has no classes. +Use the constructor function pattern instead, adding methods to the prototype. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero.component.ts' region='class'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6' region='class'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero.component.es6' region='class'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero.component.js' region='constructorproto'} + </md-tab> + + +</md-tab-group> + +### Metadata + +When writing in _TypeScript_ or _ES6-with-decorators_, +provide configuration and metadata by adorning a class with one or more *decorators*. +For example, you supply metadata to a component class by preceding its definition with a +[`@Component`](../api/core/index/Component-decorator.html) decorator function whose +argument is an object literal with metadata properties. + +In _plain ES6_, you provide metadata by attaching an `annotations` array to the _class_. +Each item in the array is a new instance of a metadata decorator created with a similar metadata object literal. + +In _ES5_, you also provide an `annotations` array but you attach it to the _constructor function_ rather than to a class. + +See these variations side-by-side: + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero.component.ts' region='metadata'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6' region='metadata'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero.component.es6' region='metadata'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero.component.js' region='metadata'} + </md-tab> + + +</md-tab-group> + +***External Template file*** + +A large component template is often kept in a separate template file. + +{@example 'cb-ts-to-js/ts/src/app/hero-title.component.html'} + +The component (`HeroTitleComponent` in this case) then references the template file in its metadata `templateUrl` property: +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-title.component.ts' region='templateUrl'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.es6' region='templateUrl'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-title.component.es6' region='templateUrl'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-title.component.js' region='templateUrl'} + </md-tab> + + +</md-tab-group> + +Note that both the _TypeScript_ and _ES6_ `templateUrl` properties identify the location of the template file _relative to the component module_. +All three metadata configurations specify the `moduleId` property +so that Angular can calculate the proper module address. + +The _ES5_ approach shown here does not support modules and therefore there is no way to calculate a _module-relative URL_. +The `templateUrl` for the _ES5_ code must specify the _path from the project root_ and +omits the irrelevant `moduleId` property. + +With the right tooling, the `moduleId` may not be needed in the other JavaScript dialects either. +But it's safest to provide it anyway. + + +{@a dsl} + +## _ES5_ DSL + +This _ES5_ pattern of creating a constructor and annotating it with metadata is so common that Angular +provides a convenience API to make it a little more compact and locates the metadata above the constructor, +as you would if you wrote in _TypeScript_ or _ES6-with-decorators_. + +This _API_ (_Application Programming Interface_) is commonly known as the _ES5 DSL_ (_Domain Specific Language_). + +Set an application namespace property (e.g., `app.HeroDslComponent`) to the result of an `ng.core.Component` function call. +Pass the same metadata object to `ng.core.Component` as you did before. +Then chain a call to the `Class` method which takes an object defining the class constructor and instance methods. + +Here is an example of the `HeroComponent`, re-written with the DSL, +next to the original _ES5_ version for comparison: + +<md-tab-group> + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero.component.js' region='dsl'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero.component.js'} + </md-tab> + + +</md-tab-group> + + + +~~~ {.callout.is-helpful} + + +<header> + Name the constructor +</header> + +A **named** constructor displays clearly in the console log +if the component throws a runtime error. +An **unnamed** constructor displays as an anonymous function (e.g., `class0`) +which is impossible to find in the source code. + + +~~~ + +### Properties with getters and setters + +_TypeScript_ and _ES6_ support with getters and setters. +Here's an example of a read-only _TypeScript_ property with a getter +that prepares a toggle-button label for the next clicked state: + +{@example 'cb-ts-to-js/ts/src/app/hero-queries.component.ts' region='defined-property'} + +This _TypeScript_ "getter" property is transpiled to an _ES5_ +<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty" + target="_blank" title="Defined Properties">defined property</a>. +The _ES5 DSL_ does not support _defined properties_ directly +but you can still create them by extracting the "class" prototype and +adding the _defined property_ in raw JavaScript like this: + +{@example 'cb-ts-to-js/js/src/app/hero-queries.component.js' region='defined-property'} + +### DSL for other classes +There are similar DSLs for other decorated classes. +You can define a directive with `ng.core.Directive`: + +<code-example> + app.MyDirective = ng.core.Directive({ + selector: '[myDirective]' + }).Class({ + ... + }); +</code-example> + +and a pipe with `ng.core.Pipe`: +<code-example> + app.MyPipe = ng.core.Pipe({ + name: 'myPipe' + }).Class({ + ... + }); + +</code-example> + + + +{@a interfaces} + +## Interfaces + +A _TypeScript_ interface helps ensure that a class implements the interface's members correctly. +We strongly recommend Angular interfaces where appropriate. +For example, the component class that implements the `ngOnInit` lifecycle hook method +should implement the `OnInit` interface. + +_TypeScript_ interfaces exist for developer convenience and are not used by Angular at runtime. +They have no physical manifestation in the generated JavaScript code. +Just implement the methods and ignore interfaces when translating code samples from _TypeScript_ to JavaScript. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-lifecycle.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-lifecycle.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-lifecycle.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-lifecycle.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-lifecycle.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + + + +{@a io-decorators} + +## Input and Output Metadata + +### Input and Output Decorators + +In _TypeScript_ and _ES6-with-decorators_, you often add metadata to class _properties_ with _property decorators_. +For example, you apply [`@Input` and `@Output` property decorators](../guide/template-syntax.html#inputs-outputs) +to public class properties that will be the target of data binding expressions in parent components. + +There is no equivalent of a property decorator in _ES5_ or _plain ES6_. +Fortunately, every property decorator has an equivalent representation in a class decorator metadata property. +A _TypeScript_ `@Input` property decorator can be represented by an item in the `Component` metadata's `inputs` array. + +You already know how to add `Component` or `Directive` class metadata in _any_ JavaScript dialect so +there's nothing fundamentally new about adding another property. +But note that what would have been _separate_ `@Input` and `@Output` property decorators for each class property are +combined in the metadata `inputs` and `outputs` _arrays_. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/confirm.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/confirm.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/confirm.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/confirm.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/confirm.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + +In the previous example, one of the public-facing binding names (`cancelMsg`) +differs from the corresponding class property name (`notOkMsg`). +That's OK but you must tell Angular about it so that it can map an external binding of `cancelMsg` +to the component's `notOkMsg` property. + +In _TypeScript_ and _ES6-with-decorators_, +you specify the special binding name in the argument to the property decorator. + +In _ES5_ and _plain ES6_ code, convey this pairing with the `propertyName: bindingName` syntax in the class metadata. + +## Dependency Injection +Angular relies heavily on [Dependency Injection](../guide/dependency-injection.html) to provide services to the objects it creates. +When Angular creates a new component, directive, pipe or another service, +it sets the class constructor parameters to instances of services provided by an _Injector_. + +The developer must tell Angular what to inject into each parameter. + +### Injection by Class Type + +The easiest and most popular technique in _TypeScript_ and _ES6-with-decorators_ is to set the constructor parameter type +to the class associated with the service to inject. + +The _TypeScript_ transpiler writes parameter type information into the generated JavaScript. +Angular reads that information at runtime and locates the corresponding service in the appropriate _Injector_.. +The _ES6-with-decorators_ transpiler does essentially the same thing using the same parameter-typing syntax. + +_ES5_ and _plain ES6_ lack types so you must identify "injectables" by attaching a **`parameters`** array to the constructor function. +Each item in the array specifies the service's injection token. + +As with _TypeScript_ the most popular token is a class, +or rather a _constructor function_ that represents a class in _ES5_ and _plain ES6_. +The format of the `parameters` array varies: + +* _plain ES6_ — nest each constructor function in a sub-array. + +* _ES5_ — simply list the constructor functions. + +When writing with _ES5 DSL_, set the `Class.constructor` property to +an array whose first parameters are the injectable constructor functions and whose +last parameter is the class constructor itself. +This format should be familiar to AngularJS developers. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-di.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-di.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-di.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-di.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-di.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + +### Injection with the @Inject decorator + +Sometimes the dependency injection token isn't a class or constructor function. + +In _TypeScript_ and _ES6-with-decorators_, you precede the class constructor parameter +by calling the `@Inject()` decorator with the injection token. +In the following example, the token is the string `'heroName'`. + +The other JavaScript dialects add a `parameters` array to the class contructor function. +Each item constains a new instance of `Inject`: + +* _plain ES6_ — each item is a new instance of `Inject(token)` in a sub-array. + +* _ES5_ — simply list the string tokens. + +When writing with _ES5 DSL_, set the `Class.constructor` property to a function definition +array as before. Create a new instance of `ng.core.Inject(token)` for each parameter. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-di-inject.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-di-inject.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-di-inject.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-di-inject.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + +### Additional Injection Decorators + +You can qualify injection behavior with injection decorators from `@angular/core`. + +In _TypeScript_ and _ES6-with-decorators_, +you precede the constructor parameters with injection qualifiers such as: +* [`@Optional`](../api/core/index/Optional-decorator.html) sets the parameter to `null` if the service is missing +* [`@Attribute`](../api/core/index/Attribute-interface.html) to inject a host element attribute value +* [`@ContentChild`](../api/core/index/ContentChild-decorator.html) to inject a content child +* [`@ViewChild`](../api/core/index/ViewChild-decorator.html) to inject a view child +* [`@Host`](../api/core/index/Host-decorator.html) to inject a service in this component or its host +* [`@SkipSelf`](../api/core/index/SkipSelf-decorator.html) to inject a service provided in an ancestor of this component + +In _plain ES6_ and _ES5_, create an instance of the equivalent injection qualifier in a nested array within the `parameters` array. +For example, you'd write `new Optional()` in _plain ES6_ and `new ng.core.Optional()` in _ES5_. + + +When writing with _ES5 DSL_, set the `Class.constructor` property to a function definition +array as before. Use a nested array to define a parameter's complete injection specification. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-title.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-title.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-title.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-title.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + + +In the example above, there is no provider for the `'titlePrefix'` token. +Without `Optional`, Angular would raise an error. +With `Optional`, Angular sets the constructor parameter to `null` +and the component displays the title without a prefix. + + +{@a host-binding} + +## Host Binding +Angular supports bindings to properties and events of the _host element_ which is the +element whose tag matches the component selector. + +### Host Decorators + +In _TypeScript_ and _ES6-with-decorators_, you can use host property decorators to bind a host +element to a component or directive. +The [`@HostBinding`](../api/core/index/HostBinding-interface.html) decorator +binds host element properties to component data properties. +The [`@HostListener`](../api/core/index/HostListener-interface.html) decorator binds +host element events to component event handlers. + +In _plain ES6_ or _ES5_, add a `host` attribute to the component metadata to achieve the +same effect as `@HostBinding` and `@HostListener`. + +The `host` value is an object whose properties are host property and listener bindings: + +* Each key follows regular Angular binding syntax: `[property]` for host bindings + or `(event)` for host listeners. +* Each value identifies the corresponding component property or method. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-host.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-host.component.es6'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-host.component.es6'} + </md-tab> + + + <md-tab label="ES5 JavaScript"> + {@example 'cb-ts-to-js/js/src/app/hero-host.component.js'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-host.component.js' region='dsl'} + </md-tab> + + +</md-tab-group> + +### Host Metadata +Some developers prefer to specify host properties and listeners +in the component metadata. +They'd _rather_ do it the way you _must_ do it _ES5_ and _plain ES6_. + +The following re-implementation of the `HeroComponent` reminds us that _any property metadata decorator_ +can be expressed as component or directive metadata in both _TypeScript_ and _ES6-with-decorators_. +These particular _TypeScript_ and _ES6_ code snippets happen to be identical. +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-host-meta.component.ts'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-host-meta.component.es6'} + </md-tab> + + +</md-tab-group> + + + +{@a view-child-decorators} + +### View and Child Decorators + +Several _property_ decorators query a component's nested view and content components. + +_View_ children are associated with element tags that appear _within_ the component's template. + +_Content_ children are associated with elements that appear _between_ the component's element tags; +they are projected into an `<ng-content>` slot in the component's template. The [`@ViewChild`](../api/core/index/ViewChild-decorator.html) and +[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html) property decorators +allow a component to query instances of other components that are used in +its view. + +In _ES5_ and _ES6_, you access a component's view children by adding a `queries` property to the component metadata. +The `queries` property value is a hash map. + +* each _key_ is the name of a component property that will hold the view child or children. +* each _value_ is a new instance of either `ViewChild` or `ViewChildren`. + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-queries.component.ts' region='view'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-queries.component.es6' region='view'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-queries.component.es6' region='view'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-queries.component.js' region='view'} + </md-tab> + + +</md-tab-group> + +The [`@ContentChild`](../api/core/index/ContentChild-decorator.html) and +[`@ContentChildren`](../api/core/index/ContentChildren-decorator.html) property decorators +allow a component to query instances of other components that have been projected +into its view from elsewhere. + +They can be added in the same way as [`@ViewChild`](../api/core/index/ViewChild-decorator.html) and +[`@ViewChildren`](../api/core/index/ViewChildren-decorator.html). + +<md-tab-group> + + <md-tab label="TypeScript"> + {@example 'cb-ts-to-js/ts/src/app/hero-queries.component.ts' region='content'} + </md-tab> + + + <md-tab label="ES6 JavaScript with decorators"> + {@example 'cb-ts-to-js/js-es6-decorators/src/app/hero-queries.component.es6' region='content'} + </md-tab> + + + <md-tab label="ES6 JavaScript"> + {@example 'cb-ts-to-js/js-es6/src/app/hero-queries.component.es6' region='content'} + </md-tab> + + + <md-tab label="ES5 JavaScript with DSL"> + {@example 'cb-ts-to-js/js/src/app/hero-queries.component.js' region='content'} + </md-tab> + + +</md-tab-group> + + + +~~~ {.alert.is-helpful} + +In _TypeScript_ and _ES6-with-decorators_ you can also use the `queries` metadata +instead of the `@ViewChild` and `@ContentChild` property decorators. + + +~~~ + + + +{@a aot} + +## AOT Compilation in _TypeScript_ only + +Angular offers two modes of template compilation, JIT (_Just-in-Time_) and +[AOT (_Ahead-of-Time_)](aot-compiler.html). +Currently the AOT compiler only works with _TypeScript_ applications because, in part, it generates +_TypeScript_ files as an intermediate result. +**AOT is not an option for pure JavaScript applications** at this time. \ No newline at end of file diff --git a/aio/content/cookbook/visual-studio-2015.md b/aio/content/cookbook/visual-studio-2015.md new file mode 100644 index 0000000000..5d9566b17d --- /dev/null +++ b/aio/content/cookbook/visual-studio-2015.md @@ -0,0 +1,171 @@ +@title +Visual Studio 2015 QuickStart + +@intro +Use Visual Studio 2015 with the QuickStart files + +@description +<a id="top"></a>Some developers prefer Visual Studio as their Integrated Development Environment (IDE). + +This cookbook describes the steps required to set up and use the +Angular QuickStart files in **Visual Studio 2015 within an ASP.NET 4.x project**. +There is no *live example* for this cookbook because it describes Visual Studio, not the application. + +<a id="asp-net-4"></a>## ASP.NET 4.x Project + +This cookbook explains how to set up the QuickStart files with an **ASP.NET 4.x project** in +Visual Studio 2015. +If you prefer a `File | New Project` experience and are using **ASP.NET Core**, +then consider the _experimental_ +<a href="http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/" target="_blank">ASP.NET Core + Angular template for Visual Studio 2015</a>. +Note that the resulting code does not map to the docs. Adjust accordingly. +The steps are as follows: + +- [Prerequisite](#prereq1): Install Node.js +- [Prerequisite](#prereq2): Install Visual Studio 2015 Update 3 +- [Prerequisite](#prereq3): Configure External Web tools +- [Prerequisite](#prereq4): Install TypeScript 2 for Visual Studio 2015 +- [Step 1](#download): Download the QuickStart files +- [Step 2](#create-project): Create the Visual Studio ASP.NET project +- [Step 3](#copy): Copy the QuickStart files into the ASP.NET project folder +- [Step 4](#restore): Restore required packages +- [Step 5](#build-and-run): Build and run the app + + +<h2 id='prereq1'> + Prerequisite: Node.js +</h2> + +Install **[Node.js® and npm](https://nodejs.org/en/download/)** +if they are not already on your machine. +**Verify that you are running node version `4.6.x` or greater, and npm `3.x.x` or greater** +by running `node -v` and `npm -v` in a terminal/console window. +Older versions produce errors. + + +<h2 id='prereq2'> + Prerequisite: Visual Studio 2015 Update 3 +</h2> + +The minimum requirement for developing Angular applications with Visual Studio is Update 3. +Earlier versions do not follow the best practices for developing applications with TypeScript. +To view your version of Visual Studio 2015, go to `Help | About Visual Studio`. + +If you don't have it, install **[Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)**. +Or use `Tools | Extensions and Updates` to update to Update 3 directly from Visual Studio 2015. + + +<h2 id='prereq3'> + Prerequisite: Configure External Web tools +</h2> + +Configure Visual Studio to use the global external web tools instead of the tools that ship with Visual Studio: + + * Open the **Options** dialog with `Tools` | `Options` + * In the tree on the left, select `Projects and Solutions` | `External Web Tools`. + * On the right, move the `$(PATH)` entry above the `$(DevEnvDir`) entries. This tells Visual Studio to + use the external tools (such as npm) found in the global path before using its own version of the external tools. + * Click OK to close the dialog. + * Restart Visual Studio for this change to take effect. + +Visual Studio will now look first for external tools in the current workspace and +if not found then look in the global path and if it is not found there, Visual Studio +will use its own versions of the tools. + + +<h2 id='prereq4'> + Prerequisite: Install TypeScript 2 for Visual Studio 2015 +</h2> + +While Visual Studio Update 3 ships with TypeScript support out of the box, it currently doesn’t ship with TypeScript 2, +which you need to develop Angular applications. + +To install TypeScript 2: + * Download and install **[TypeScript 2.0 for Visual Studio 2015](http://download.microsoft.com/download/6/D/8/6D8381B0-03C1-4BD2-AE65-30FF0A4C62DA/TS2.0.3-TS-release20-nightly-20160921.1/TypeScript_Dev14Full.exe)** + * OR install it with npm: `npm install -g typescript@2.0`. + +You can find out more about TypeScript 2 support in Visual studio **[here](https://blogs.msdn.microsoft.com/typescript/2016/09/22/announcing-typescript-2-0/)** + +At this point, Visual Studio is ready. It’s a good idea to close Visual Studio and +restart it to make sure everything is clean. + + +<h2 id='download'> + Step 1: Download the QuickStart files +</h2> + +[Download the QuickStart source](https://github.com/angular/quickstart) +from github. If you downloaded as a zip file, extract the files. + + +<h2 id='create-project'> + Step 2: Create the Visual Studio ASP.NET project +</h2> + +Create the ASP.NET 4.x project in the usual way as follows: + +* In Visual Studio, select `File` | `New` | `Project` from the menu. +* In the template tree, select `Templates` | `Visual C#` (or `Visual Basic`) | `Web`. +* Select the `ASP.NET Web Application` template, give the project a name, and click OK. +* Select the desired ASP.NET 4.5.2 template and click OK. + +In this cookbook we'll select the `Empty` template with no added folders, +no authentication and no hosting. Pick the template and options appropriate for your project. + + +<h2 id='copy'> + Step 3: Copy the QuickStart files into the ASP.NET project folder +</h2> + +Copy the QuickStart files we downloaded from github into the folder containing the `.csproj` file. +Include the files in the Visual Studio project as follows: + +* Click the `Show All Files` button in Solution Explorer to reveal all of the hidden files in the project. +* Right-click on each folder/file to be included in the project and select `Include in Project`. + Minimally, include the following folder/files: + * app folder (answer *No* if asked to search for TypeScript Typings) + * styles.css + * index.html + * package.json + * tsconfig.json + + +<h2 id='restore'> + Step 4: Restore the required packages +</h2> + +Restore the packages required for an Angular application as follows: + +* Right-click on the `package.json` file in Solution Explorer and select `Restore Packages`. + <br>This uses `npm` to install all of the packages defined in the `package.json` file. + It may take some time. +* If desired, open the Output window (`View` | `Output`) to watch the npm commands execute. +* Ignore the warnings. +* When the restore is finished, a message should say: `npm command completed with exit code 0`. +* Click the `Refresh` icon in Solution Explorer. +* **Do not** include the `node_modules` folder in the project. Let it be a hidden project folder. + + +<h2 id='build-and-run'> + Step 5: Build and run the app +</h2> + +First, ensure that `index.html` is set as the start page. +Right-click `index.html` in Solution Explorer and select option `Set As Start Page`. + +Build and launch the app with debugger by clicking the **Run** button or press `F5`. +It's faster to run without the debugger by pressing `Ctrl-F5`.The default browser opens and displays the QuickStart sample application. + +Try editing any of the project files. *Save* and refresh the browser to +see the changes. + + +<h2 id='routing'> + Note on Routing Applications +</h2> + +If this application used the Angular router, a browser refresh could return a *404 - Page Not Found*. +Look at the address bar. Does it contain a navigation url (a "deep link") ... any path other than `/` or `/index.html`? + +You'll have to configure the server to return `index.html` for these requests. +Until you do, remove the navigation path and refresh again. \ No newline at end of file diff --git a/aio/content/guide/animations.md b/aio/content/guide/animations.md new file mode 100644 index 0000000000..4046caadc3 --- /dev/null +++ b/aio/content/guide/animations.md @@ -0,0 +1,370 @@ +@title +Animations + +@intro +A guide to Angular's animation system. + +@description +Motion is an important aspect in the design of modern web applications. Good +user interfaces transition smoothly between states with engaging animations +that call attention where it's needed. Well-designed animations can make a UI not only +more fun but also easier to use. + +Angular's animation system lets you build animations that run with the same kind of native +performance found in pure CSS animations. You can also tightly integrate your +animation logic with the rest of your application code, for ease of control. + + +~~~ {.alert.is-helpful} + +Angular animations are built on top of the standard [Web Animations API](https://w3c.github.io/web-animations/) +and run natively on [browsers that support it](http://caniuse.com/#feat=web-animation). + +For other browsers, a polyfill is required. Grab +[`web-animations.min.js` from GitHub](https://github.com/web-animations/web-animations-js) and +add it to your page. + + + +~~~ + +# Contents + +* [Example: Transitioning between two states](#example-transitioning-between-states). +* [States and transitions](#states-and-transitions). +* [Example: Entering and leaving](#example-entering-and-leaving). +* [Example: Entering and leaving from different states](#example-entering-and-leaving-from-different-states). +* [Animatable properties and units](#animatable-properties-and-units). +* [Automatic property calculation](#automatic-property-calculation). +* [Animation timing](#animation-timing). +* [Multi-step animations with keyframes](#multi-step-animations-with-keyframes). +* [Parallel animation groups](#parallel-animation-groups). +* [Animation callbacks](#animation-callbacks). + +The examples in this page are available as a <live-example></live-example>. + + +{@a example-transitioning-between-states} + +## Quickstart example: Transitioning between two states +<figure> + <img src="/resources/images/devguide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px"> </img> +</figure> + +You can build a simple animation that transitions an element between two states +driven by a model attribute. + +Animations are defined inside `@Component` metadata. Before you can add animations, you need +to import a few animation-specific functions: + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts' region='imports'} + +With these, you can define an *animation trigger* called `heroState` in the component +metadata. It uses animations to transition between two states: `active` and `inactive`. When a +hero is active, the element appears in a slightly larger size and lighter color. + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts' region='animationdef'} + + + +~~~ {.alert.is-helpful} + +In this example, you are defining animation styles (color and transform) inline in the +animation metadata. + + +~~~ + +Now, using the `[@triggerName]` syntax, attach the animation that you just defined to +one or more elements in the component's template. + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts' region='template'} + +Here, the animation trigger applies to every element repeated by an `ngFor`. Each of +the repeated elements animates independently. The value of the +attribute is bound to the expression `hero.state` and is always either `active` or `inactive`. + +With this setup, an animated transition appears whenever a hero object changes state. +Here's the full component implementation: + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts'} + +## States and transitions + +Angular animations are defined as logical **states** and **transitions** +between states. + +An animation state is a string value that you define in your application code. In the example +above, the states `'active'` and `'inactive'` are based on the logical state of +hero objects. The source of the state can be a simple object attribute, as it was in this case, +or it can be a value computed in a method. The important thing is that you can read it into the +component's template. + +You can define *styles* for each animation state: + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts' region='states'} + +These `state` definitions specify the *end styles* of each state. +They are applied to the element once it has transitioned to that state, and stay +*as long as it remains in that state*. In effect, you're defining what styles the element has in different states. + +After you define states, you can define *transitions* between the states. Each transition +controls the timing of switching between one set of styles and the next: + + +{@example 'animations/ts/src/app/hero-list-basic.component.ts' region='transitions'} + + +<figure class='image-display'> + <img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400"> </img> +</figure> + +If several transitions have the same timing configuration, you can combine +them into the same `transition` definition: + + +{@example 'animations/ts/src/app/hero-list-combined-transitions.component.ts' region='transitions'} + +When both directions of a transition have the same timing, as in the previous +example, you can use the shorthand syntax `<=>`: + + +{@example 'animations/ts/src/app/hero-list-twoway.component.ts' region='transitions'} + +You can also apply a style during an animation but not keep it around +after the animation finishes. You can define such styles inline, in the `transition`. In this example, +the element receives one set of styles immediately and is then animated to the next. +When the transition finishes, none of these styles are kept because they're not +defined in a `state`. + + +{@example 'animations/ts/src/app/hero-list-inline-styles.component.ts' region='transitions'} + +### The wildcard state `*` + +The `*` ("wildcard") state matches *any* animation state. This is useful for defining styles and +transitions that apply regardless of which state the animation is in. For example: + +* The `active => *` transition applies when the element's state changes from `active` to anything else. +* The `* => *` transition applies when *any* change between two states takes place. + +<figure class='image-display'> + <img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400"> </img> +</figure> + +### The `void` state + +The special state called `void` can apply to any animation. It applies +when the element is *not* attached to a view, perhaps because it has not yet been +added or because it has been removed. The `void` state is useful for defining enter and +leave animations. + +For example the `* => void` transition applies when the element leaves the view, +regardless of what state it was in before it left. + +<figure class='image-display'> + <img src="/resources/images/devguide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400"> </img> +</figure> + +The wildcard state `*` also matches `void`. + +## Example: Entering and leaving +<figure> + <img src="/resources/images/devguide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;"> </img> +</figure> + +Using the `void` and `*` states you can define transitions that animate the +entering and leaving of elements: + +* Enter: `void => *` +* Leave: `* => void` + + +{@example 'animations/ts/src/app/hero-list-enter-leave.component.ts' region='animationdef'} + +Note that in this case the styles are applied to the void state directly in the +transition definitions, and not in a separate `state(void)` definition. Thus, the transforms +are different on enter and leave: the element enters from the left +and leaves to the right. + +These two common animations have their own aliases: +<code-example language="typescript"> + transition(':enter', [ ... ]); // void => * + transition(':leave', [ ... ]); // * => void + +</code-example> + +## Example: Entering and leaving from different states +<figure> + <img src="/resources/images/devguide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px"> </img> +</figure> + +You can also combine this animation with the earlier state transition animation by +using the hero state as the animation state. This lets you configure +different transitions for entering and leaving based on what the state of the hero +is: + +* Inactive hero enter: `void => inactive` +* Active hero enter: `void => active` +* Inactive hero leave: `inactive => void` +* Active hero leave: `active => void` + +This gives you fine-grained control over each transition: + +<figure class='image-display'> + <img src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400"> </img> +</figure> + + + +{@example 'animations/ts/src/app/hero-list-enter-leave-states.component.ts' region='animationdef'} + +## Animatable properties and units + +Since Angular's animation support builds on top of Web Animations, you can animate any property +that the browser considers *animatable*. This includes positions, sizes, transforms, colors, +borders, and many others. The W3C maintains +[a list of animatable properties](https://www.w3.org/TR/css3-transitions/#animatable-properties) +on its [CSS Transitions page](https://www.w3.org/TR/css3-transitions). + +For positional properties that have a numeric value, you can define a unit by providing +the value as a string with the appropriate suffix: + +* `'50px'` +* `'3em'` +* `'100%'` + +If you don't provide a unit when specifying dimension, Angular assumes the default of `px`: + +* `50` is the same as saying `'50px'` + +## Automatic property calculation +<figure> + <img src="/resources/images/devguide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px"> </img> +</figure> + +Sometimes you don't know the value of a dimensional style property until runtime. +For example, elements often have widths and heights that +depend on their content and the screen size. These properties are often tricky +to animate with CSS. + +In these cases, you can use a special `*` property value so that the value of the +property is computed at runtime and then plugged into the animation. + +In this example, the leave animation takes whatever height the element has before it +leaves and animates from that height to zero: + + +{@example 'animations/ts/src/app/hero-list-auto.component.ts' region='animationdef'} + +## Animation timing + +There are three timing properties you can tune for every animated transition: +the duration, the delay, and the easing function. They are all combined into +a single transition *timing string*. + +### Duration + +The duration controls how long the animation takes to run from start to finish. +You can define a duration in three ways: + +* As a plain number, in milliseconds: `100` +* In a string, as milliseconds: `'100ms'` +* In a string, as seconds: `'0.1s'` + +### Delay + +The delay controls the length of time between the animation trigger and the beginning +of the transition. You can define one by adding it to the same string +following the duration. It also has the same format options as the duration: + +* Wait for 100ms and then run for 200ms: `'0.2s 100ms'` + +### Easing + +The [easing function](http://easings.net/) controls how the animation accelerates +and decelerates during its runtime. For example, an `ease-in` function causes +the animation to begin relatively slowly but pick up speed as it progresses. You +can control the easing by adding it as a *third* value in the string after the duration +and the delay (or as the *second* value when there is no delay): + +* Wait for 100ms and then run for 200ms, with easing: `'0.2s 100ms ease-out'` +* Run for 200ms, with easing: `'0.2s ease-in-out'` + +<figure> + <img src="/resources/images/devguide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px"> </img> +</figure> + +### Example + +Here are a couple of custom timings in action. Both enter and leave last for +200 milliseconds but they have different easings. The leave begins after a +slight delay: + + +{@example 'animations/ts/src/app/hero-list-timings.component.ts' region='animationdef'} + +## Multi-step animations with keyframes +<figure> + <img src="/resources/images/devguide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px"> </img> +</figure> + +Animation *keyframes* go beyond a simple transition to a more intricate animation +that goes through one or more intermediate styles when transitioning between two sets of styles. + +For each keyframe, you specify an *offset* that defines at which point +in the animation that keyframe applies. The offset is a number between zero, +which marks the beginning of the animation, and one, which marks the end. + +This example adds some "bounce" to the enter and leave animations with +keyframes: + + +{@example 'animations/ts/src/app/hero-list-multistep.component.ts' region='animationdef'} + +Note that the offsets are *not* defined in terms of absolute time. They are relative +measures from zero to one. The final timeline of the animation is based on the combination +of keyframe offsets, duration, delay, and easing. + +Defining offsets for keyframes is optional. If you omit them, offsets with even +spacing are automatically assigned. For example, three keyframes without predefined +offsets receive offsets `0`, `0.5`, and `1`. +## Parallel animation groups +<figure> + <img src="/resources/images/devguide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px"> </img> +</figure> + +You've seen how to animate multiple style properties at the same time: +just put all of them into the same `style()` definition. + +But you may also want to configure different *timings* for animations that happen +in parallel. For example, you may want to animate two CSS properties but use a +different easing function for each one. + +For this you can use animation *groups*. In this example, using groups both on +enter and leave allows for two different timing configurations. Both +are applied to the same element in parallel, but run independently of each other: + + +{@example 'animations/ts/src/app/hero-list-groups.component.ts' region='animationdef'} + +One group animates the element transform and width; the other group animates the opacity. +## Animation callbacks + +A callback is fired when an animation is started and also when it is done. + +In the keyframes example, you have a `trigger` called `@flyInOut`. There you can hook +those callbacks like this: + + +{@example 'animations/ts/src/app/hero-list-multistep.component.ts' region='template'} + +The callbacks receive an `AnimationTransitionEvent` which contains useful properties such as `fromState`, +`toState` and `totalTime`. + +Those callbacks will fire whether or not an animation is picked up. \ No newline at end of file diff --git a/aio/content/guide/appmodule.md b/aio/content/guide/appmodule.md new file mode 100644 index 0000000000..f42b13c30a --- /dev/null +++ b/aio/content/guide/appmodule.md @@ -0,0 +1,157 @@ +@title +AppModule: the root module + +@intro +Tell Angular how to construct and bootstrap the app in the root "AppModule". + +@description +An Angular module class describes how the application parts fit together. +Every application has at least one Angular module, the _root_ module +that you [bootstrap](#main) to launch the application. +You can call it anything you want. The conventional name is `AppModule`. + +The [setup](setup.html) instructions produce a new project with the following minimal `AppModule`. +You'll evolve this module as your application grows. + + +{@example 'setup/ts/src/app/app.module.ts'} + +After the `import` statements, you come to a class adorned with the +**`@NgModule`** [_decorator_](glossary.html#decorator '"Decorator" explained'). + +The `@NgModule` decorator identifies `AppModule` as an Angular module class (also called an `NgModule` class). +`@NgModule` takes a _metadata_ object that tells Angular how to compile and launch the application. + +* **_imports_** — the `BrowserModule` that this and every application needs to run in a browser. +* **_declarations_** — the application's lone component, which is also ... +* **_bootstrap_** — the _root_ component that Angular creates and inserts into the `index.html` host web page. + +The [Angular Modules (NgModule)](ngmodule.html) guide dives deeply into the details of Angular modules. +All you need to know at the moment is a few basics about these three properties. + + +{@a imports} +### The _imports_ array + +Angular modules are a way to consolidate features that belong together into discrete units. +Many features of Angular itself are organized as Angular modules. +HTTP services are in the `HttpModule`. The router is in the `RouterModule`. +Eventually you may create a feature module. + +Add a module to the `imports` array when the application requires its features. + +_This_ application, like most applications, executes in a browser. +Every application that executes in a browser needs the `BrowserModule` from `@angular/platform-browser`. +So every such application includes the `BrowserModule` in its _root_ `AppModule`'s `imports` array. +Other guide and cookbook pages will tell you when you need to add additional modules to this array. + + +~~~ {.alert.is-important} + +**Only `NgModule` classes** go in the `imports` array. Do not put any other kind of class in `imports`. + + +~~~ + + +The `import` statements at the top of the file and the Angular module's `imports` array +are unrelated and have completely different jobs. + +The _JavaScript_ `import` statements give you access to symbols _exported_ by other files +so you can reference them within _this_ file. +You add `import` statements to almost every application file. +They have nothing to do with Angular and Angular knows nothing about them. + +The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object. +It tells Angular about specific _other_ Angular modules — all of them classes decorated with `@NgModule` — +that the application needs to function properly. + +{@a declarations} +### The _declarations_ array + +You tell Angular which components belong to the `AppModule` by listing it in the module's `declarations` array. +As you create more components, you'll add them to `declarations`. + +You must declare _every_ component in an `NgModule` class. +If you use a component without declaring it, you'll see a clear error message in the browser console. + +You'll learn to create two other kinds of classes — +[directives](attribute-directives.html) and [pipes](pipes.html) — +that you must also add to the `declarations` array. + + +~~~ {.alert.is-important} + +**Only _declarables_** — _components_, _directives_ and _pipes_ — belong in the `declarations` array. +Do not put any other kind of class in `declarations`; _not_ `NgModule` classes, _not_ service classes, _not_ model classes. + + +~~~ + + + +{@a bootstrap-array} +### The _bootstrap_ array + +You launch the application by [_bootstrapping_](#main) the root `AppModule`. +Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array +and inserts each one into the browser DOM. + +Each bootstrapped component is the base of its own tree of components. +Inserting a bootstrapped component usually triggers a cascade of component creations that fill out that tree. + +While you can put more than one component tree on a host web page, that's not typical. +Most applications have only one component tree and they bootstrap a single _root_ component. + +You can call the one _root_ component anything you want but most developers call it `AppComponent`. + +Which brings us to the _bootstrapping_ process itself. + + +{@a main} + +<l-main-section> + +</l-main-section> + +## Bootstrap in _main.ts_ + +There are many ways to bootstrap an application. +The variations depend upon how you want to compile the application and where you want to run it. + +In the beginning, you will compile the application dynamically with the _Just-in-Time (JIT)_ compiler +and you'll run it in a browser. You can learn about other options later. + +The recommended place to bootstrap a JIT-compiled browser application is in a separate file +in the `src` folder named `src/main.ts` + +{@example 'setup/ts/src/main.ts'} + +This code creates a browser platform for dynamic (JIT) compilation and +bootstraps the `AppModule` described above. + +The _bootstrapping_ process sets up the execution environment, +digs the _root_ `AppComponent` out of the module's `bootstrap` array, +creates an instance of the component and inserts it within the element tag identified by the component's `selector`. + +The `AppComponent` selector — here and in most documentation samples — is `my-app` +so Angular looks for a `<my-app>` tag in the `index.html` like this one ... + +{@example 'setup/ts/src/index.html' region='my-app'} + +... and displays the `AppComponent` there. + +This file is very stable. Once you've set it up, you may never change it again. + +<l-main-section> + +</l-main-section> + +## More about Angular Modules + +Your initial app has only a single module, the _root_ module. +As your app grows, you'll consider subdividing it into multiple "feature" modules, +so of which can be loaded later ("lazy loaded") if and when the user chooses +to visit those features. + +When you're ready to explore these possibilities, visit the [Angular Modules (NgModule)](ngmodule.html) guide. \ No newline at end of file diff --git a/aio/content/guide/architecture.md b/aio/content/guide/architecture.md new file mode 100644 index 0000000000..de9ffb13ee --- /dev/null +++ b/aio/content/guide/architecture.md @@ -0,0 +1,401 @@ +@title +Architecture Overview + +@intro +The basic building blocks of Angular applications + +@description +You write Angular applications by composing HTML *templates* with Angularized markup, +writing *component* classes to manage those templates, adding application logic in *services*, +and boxing components and services in *modules*. + +Then you launch the app by *bootstrapping* the _root module_. +Angular takes over, presenting your application content in a browser and +responding to user interactions according to the instructions you've provided. + +Of course, there is more to it than this. +You'll learn the details in the pages that follow. For now, focus on the big picture. + +<figure> + <img src="/resources/images/devguide/architecture/overview2.png" alt="overview" style="margin-left:-40px;" width="700"> </img> +</figure> + +The architecture diagram identifies the eight main building blocks of an Angular application: + +* [Modules](#modules) +* [Components](#components) +* [Templates](#templates) +* [Metadata](#metadata) +* [Data binding](#data-binding) +* [Directives](#directives) +* [Services](#services) +* [Dependency injection](#dependency-injection) + +Learn these building blocks, and you're on your way. + + +<p> + The code referenced on this page is available as a <live-example></live-example>. +</p> + + +## Modules +<figure> + <img src="/resources/images/devguide/architecture/module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +### Angular libraries + +<figure> + <img src="/resources/images/devguide/architecture/library-module.png" alt="Component" align="left" style="width:240px; margin-left:-40px;margin-right:10px"> </img> +</figure> + + +<div class='l-hr'> + +</div> + + +## Components + +<figure> + <img src="/resources/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +A _component_ controls a patch of screen called a *view*. + +For example, the following views are controlled by components: + +* The app root with the navigation links. +* The list of heroes. +* The hero editor. + +You define a component's application logic—what it does to support the view—inside a class. +The class interacts with the view through an API of properties and methods. + +<a id="component-code"></a> +For example, this `HeroListComponent` has a `heroes` property that returns !{_an} !{_array} of heroes +that it acquires from a service. +`HeroListComponent` also has a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list. +Angular creates, updates, and destroys components as the user moves through the application. +Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](lifecycle-hooks.html), like `ngOnInit()` declared above. + +<div class='l-hr'> + +</div> + + +## Templates +<figure> + <img src="/resources/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +You define a component's view with its companion **template**. A template is a form of HTML +that tells Angular how to render the component. + +A template looks like regular HTML, except for a few differences. Here is a +template for our `HeroListComponent`: + + +{@example 'architecture/ts/src/app/hero-list.component.html'} + +Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<hero-detail>` uses Angular's [template syntax](template-syntax.html). + + +In the last line of the template, the `<hero-detail>` tag is a custom element that represents a new component, `HeroDetailComponent`. + +The `HeroDetailComponent` is a *different* component than the `HeroListComponent` you've been reviewing. +The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the +hero that the user selects from the list presented by the `HeroListComponent`. +The `HeroDetailComponent` is a **child** of the `HeroListComponent`. + +<figure> + <img src="/resources/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Notice how `<hero-detail>` rests comfortably among native HTML elements. Custom components mix seamlessly with native HTML in the same layouts. +<br class="l-clear-both"> +<div class='l-hr'> + +</div> + + +## Metadata +<figure> + <img src="/resources/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +<p style="padding-top:10px">Metadata tells Angular how to process a class.</p> +<br class="l-clear-both">[Looking back at the code](#component-code) for `HeroListComponent`, you can see that it's just a class. +There is no evidence of a framework, no "Angular" in it at all. + +In fact, `HeroListComponent` really is *just a class*. It's not a component until you *tell Angular about it*. + +To tell Angular that `HeroListComponent` is a component, attach **metadata** to the class. + +In !{_Lang}, you attach metadata by using !{_a} **!{_decorator}**. +Here's some metadata for `HeroListComponent`: +Here is the `@Component` !{_decorator}, which identifies the class +immediately below it as a component class. +<ul if-docs="ts"><li>`moduleId`: sets the source of the base address (`module.id`) for module-relative URLs such as the `templateUrl`.</ul> + +- `selector`: CSS selector that tells Angular to create and insert an instance of this component +where it finds a `<hero-list>` tag in *parent* HTML. +For example, if an app's HTML contains `<hero-list></hero-list>`, then +Angular inserts an instance of the `HeroListComponent` view between those tags. + +- `templateUrl`: module-relative address of this component's HTML template, shown [above](#templates). +- `providers`: !{_array} of **dependency injection providers** for services that the component requires. +This is one way to tell Angular that the component's constructor requires a `HeroService` +so it can get the list of heroes to display. + +<figure> + <img src="/resources/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +The metadata in the `@Component` tells Angular where to get the major building blocks you specify for the component. + +The template, metadata, and component together describe a view. + +Apply other metadata !{_decorator}s in a similar fashion to guide Angular behavior. +`@Injectable`, `@Input`, and `@Output` are a few of the more popular !{_decorator}s.<br class="l-clear-both">The architectural takeaway is that you must add metadata to your code +so that Angular knows what to do. + +<div class='l-hr'> + +</div> + + +## Data binding +Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses +into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to +read as any experienced jQuery programmer can attest. +<figure> + <img src="/resources/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px"> </img> +</figure> + +Angular supports **data binding**, +a mechanism for coordinating parts of a template with parts of a component. +Add binding markup to the template HTML to tell Angular how to connect both sides. + +As the diagram shows, there are four forms of data binding syntax. Each form has a direction — to the DOM, from the DOM, or in both directions.<br class="l-clear-both">The `HeroListComponent` [example](#templates) template has three forms: +* The `{{hero.name}}` [*interpolation*](displaying-data.html#interpolation) +displays the component's `hero.name` property value within the `<li>` element. + +* The `[hero]` [*property binding*](template-syntax.html#property-binding) passes the value of `selectedHero` from +the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`. + +* The `(click)` [*event binding*](user-input.html#click) calls the component's `selectHero` method when the user clicks a hero's name. + +**Two-way data binding** is an important fourth form +that combines property and event binding in a single notation, using the `ngModel` directive. +Here's an example from the `HeroDetailComponent` template: +In two-way binding, a data property value flows to the input box from the component as with property binding. +The user's changes also flow back to the component, resetting the property to the latest value, +as with event binding. + +Angular processes *all* data bindings once per JavaScript event cycle, +from the root of the application component tree through all child components. + +<figure> + <img src="/resources/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Data binding plays an important role in communication +between a template and its component.<br class="l-clear-both"> +<figure> + <img src="/resources/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Data binding is also important for communication between parent and child components.<br class="l-clear-both"> +<div class='l-hr'> + +</div> + + +## Directives +<figure> + <img src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Angular templates are *dynamic*. When Angular renders them, it transforms the DOM +according to the instructions given by **directives**. + +A directive is a class with a `@Directive` !{_decorator}. +A component is a *directive-with-a-template*; +a `@Component` !{_decorator} is actually a `@Directive` !{_decorator} extended with template-oriented features. +<br class="l-clear-both"> + +While **a component is technically a directive**, +components are so distinctive and central to Angular applications that this architectural overview separates components from directives.Two *other* kinds of directives exist: _structural_ and _attribute_ directives. + +They tend to appear within an element tag as attributes do, +sometimes by name but more often as the target of an assignment or a binding. + +**Structural** directives alter layout by adding, removing, and replacing elements in DOM. + +The [example template](#templates) uses two built-in structural directives: +* [`*ngFor`](displaying-data.html#ngFor) tells Angular to stamp out one `<li>` per hero in the `heroes` list. +* [`*ngIf`](displaying-data.html#ngIf) includes the `HeroDetail` component only if a selected hero exists. +**Attribute** directives alter the appearance or behavior of an existing element. +In templates they look like regular HTML attributes, hence the name. + +The `ngModel` directive, which implements two-way data binding, is +an example of an attribute directive. `ngModel` modifies the behavior of +an existing element (typically an `<input>`) +by setting its display value property and responding to change events. +Angular has a few more directives that either alter the layout structure +(for example, [ngSwitch](template-syntax.html#ngSwitch)) +or modify aspects of DOM elements and components +(for example, [ngStyle](template-syntax.html#ngStyle) and [ngClass](template-syntax.html#ngClass)). + +Of course, you can also write your own directives. Components such as +`HeroListComponent` are one kind of custom directive. +<!-- PENDING: link to where to learn more about other kinds! --> + +<div class='l-hr'> + +</div> + + +## Services +<figure> + <img src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px"> </img> +</figure> + +_Service_ is a broad category encompassing any value, function, or feature that your application needs. + +Almost anything can be a service. +A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well.<br class="l-clear-both">Examples include: +* logging service +* data service +* message bus +* tax calculator +* application configuration + +There is nothing specifically _Angular_ about services. Angular has no definition of a service. +There is no service base class, and no place to register a service. + +Yet services are fundamental to any Angular application. Components are big consumers of services. + +Here's an example of a service class that logs to the browser console: +Here's a `HeroService` that uses a !{_PromiseLinked} to fetch heroes. +The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work. +Services are everywhere. + +Component classes should be lean. They don't fetch data from the server, +validate user input, or log directly to the console. +They delegate such tasks to services. + +A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template) +and the application logic (which often includes some notion of a _model_). +A good component presents properties and methods for data binding. +It delegates everything nontrivial to services. + +Angular doesn't *enforce* these principles. +It won't complain if you write a "kitchen sink" component with 3000 lines. + +Angular does help you *follow* these principles by making it easy to factor your +application logic into services and make those services available to components through *dependency injection*. + +<div class='l-hr'> + +</div> + + +## Dependency injection +<figure> + <img src="/resources/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +_Dependency injection_ is a way to supply a new instance of a class +with the fully-formed dependencies it requires. Most dependencies are services. +Angular uses dependency injection to provide new components with the services they need.<br class="l-clear-both">Angular can tell which services a component needs by looking at the types of its constructor parameters. +For example, the constructor of your `HeroListComponent` needs a `HeroService`: +When Angular creates a component, it first asks an **injector** for +the services that the component requires. + +An injector maintains a container of service instances that it has previously created. +If a requested service instance is not in the container, the injector makes one and adds it to the container +before returning the service to Angular. +When all requested services have been resolved and returned, +Angular can call the component's constructor with those services as arguments. +This is *dependency injection*. + +The process of `HeroService` injection looks a bit like this: +<figure> + <img src="/resources/images/devguide/architecture/injector-injects.png" alt="Service"> </img> +</figure> + +If the injector doesn't have a `HeroService`, how does it know how to make one? + +In brief, you must have previously registered a **provider** of the `HeroService` with the injector. +A provider is something that can create or return a service, typically the service class itself. +Alternatively, register at a component level in the `providers` property of the `@Component` metadata: +Registering at a component level means you get a new instance of the +service with each new instance of that component. + +<!-- We've vastly oversimplified dependency injection for this overview. +The full story is in the [dependency injection](dependency-injection.html) page. --> + +Points to remember about dependency injection: + +* Dependency injection is wired into the Angular framework and used everywhere. + +* The *injector* is the main mechanism. + * An injector maintains a *container* of service instances that it created. + * An injector can create a new service instance from a *provider*. + +* A *provider* is a recipe for creating a service. + +* Register *providers* with injectors. + +<div class='l-hr'> + +</div> + + +## Wrap up + +You've learned the basics about the eight main building blocks of an Angular application: + +* [Modules](#modules) +* [Components](#components) +* [Templates](#templates) +* [Metadata](#metadata) +* [Data binding](#data-binding) +* [Directives](#directives) +* [Services](#services) +* [Dependency injection](#dependency-injection) + +That's a foundation for everything else in an Angular application, +and it's more than enough to get going. +But it doesn't include everything you need to know. + +Here is a brief, alphabetical list of other important Angular features and services. +Most of them are covered in this documentation (or soon will be). + +> [**Animations**](animations.html): Animate component behavior +without deep knowledge of animation techniques or CSS with Angular's animation library. + +> **Change detection**: The change detection documentation will cover how Angular decides that a component property value has changed, +when to update the screen, and how it uses **zones** to intercept asynchronous activity and run its change detection strategies. + +> **Events**: The events documentation will cover how to use components and services to raise events with mechanisms for +publishing and subscribing to events. + +> [**Forms**](forms.html): Support complex data entry scenarios with HTML-based validation and dirty checking. + +> [**HTTP**](server-communication.html): Communicate with a server to get data, save data, and invoke server-side actions with an HTTP client. + +> [**Lifecycle hooks**](lifecycle-hooks.html): Tap into key moments in the lifetime of a component, from its creation to its destruction, +by implementing the lifecycle hook interfaces. + +> [**Pipes**](pipes.html): Use pipes in your templates to improve the user experience by transforming values for display. Consider this `currency` pipe expression: +> +> > `price | currency:'USD':true` +> +> It displays a price of 42.33 as `$42.33`. + +> [**Router**](router.html): Navigate from page to page within the client + application and never leave the browser. diff --git a/aio/content/guide/attribute-directives.md b/aio/content/guide/attribute-directives.md new file mode 100644 index 0000000000..25c9a62e0f --- /dev/null +++ b/aio/content/guide/attribute-directives.md @@ -0,0 +1,396 @@ +@title +Attribute Directives + +@intro +Attribute directives attach behavior to elements. + +@description +An **Attribute** directive changes the appearance or behavior of a DOM element. + +# Contents + + +* [Directives overview](#directive-overview) +* [Build a simple attribute directive](#write-directive) +* [Apply the attribute directive to an element in a template](#apply-directive) +* [Respond to user-initiated events](#respond-to-user) +* [Pass values into the directive with an _@Input_ data binding](#bindings) +* [Bind to a second property](#second-property) + +Try the <live-example title="Attribute Directive example"></live-example>. + + + +{@a directive-overview} +## Directives overview + +There are three kinds of directives in Angular: + +1. Components—directives with a template. +1. Structural directives—change the DOM layout by adding and removing DOM elements. +1. Attribute directives—change the appearance or behavior of an element, component, or another directive. + +*Components* are the most common of the three directives. +You saw a component for the first time in the [QuickStart](../quickstart.html) guide. + +*Structural Directives* change the structure of the view. +Two examples are [NgFor](template-syntax.html#ngFor) and [NgIf](template-syntax.html#ngIf). +Learn about them in the [Structural Directives](structural-directives.html) guide. + +*Attribute directives* are used as attributes of elements. +The built-in [NgStyle](template-syntax.html#ngStyle) directive in the [Template Syntax](template-syntax.html) guide, for example, +can change several element styles at the same time. + + + +{@a write-directive} +## Build a simple attribute directive +An attribute directive minimally requires building a controller class annotated with +`@Directive`, which specifies the selector that identifies +the attribute. +The controller class implements the desired directive behavior. + +This page demonstrates building a simple _myHighlight_ attribute +directive to set an element's background color +when the user hovers over that element. You can apply it like this: + + +{@example 'attribute-directives/ts/src/app/app.component.1.html' region='applied'} + +### Write the directive code +Follow the [setup](setup.html) instructions for creating a new local project +named <span ngio-ex>attribute-directives</span>. +Create the following source file in `src/app` with the following code: + +{@example 'attribute-directives/ts/src/app/highlight.directive.1.ts'} + +`@Directive` requires a CSS selector to identify +the HTML in the template that is associated with the directive. +The [CSS selector for an attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) +is the attribute name in square brackets. +Here, the directive's selector is `[myHighlight]`. +Angular locates all elements in the template that have an attribute named `myHighlight`. +### Why not call it "highlight"? +Though *highlight* is a more concise name than *myHighlight* and would work, +a best practice is to prefix selector names to ensure +they don't conflict with standard HTML attributes. +This also reduces the risk of colliding with third-party directive names. + +Make sure you do **not** prefix the `highlight` directive name with **`ng`** because +that prefix is reserved for Angular and using it could cause bugs that are difficult to diagnose. For a simple demo, the short prefix, `my`, helps distinguish your custom directive. + +<p> + After the <code> @Directive </code> metadata comes the directive's controller class, called <code> HighlightDirective </code> , which contains the logic for the directive. +</p> + +Angular creates a new instance of the directive's controller class for +each matching element, injecting an Angular `ElementRef` +into the constructor. +`ElementRef` is a service that grants direct access to the DOM element +through its `nativeElement` property. + + + +{@a apply-directive} +## Apply the attribute directive +To use the new `HighlightDirective`, create a template that +applies the directive as an attribute to a paragraph (`<p>`) element. +In Angular terms, the `<p>` element is the attribute **host**. +<p> + Put the template in its own <code> </code> file that looks like this: +</p> + + + +{@example 'attribute-directives/ts/src/app/app.component.1.html'} + +Now reference this template in the `AppComponent`: + +{@example 'attribute-directives/ts/src/app/app.component.ts'} + +Next, add an `import` statement to fetch the `Highlight` directive and +add that class to the `declarations` NgModule metadata. This way Angular +recognizes the directive when it encounters `myHighlight` in the template. + +{@example 'attribute-directives/ts/src/app/app.module.ts'} + +Now when the app runs, the `myHighlight` directive highlights the paragraph text. + +<figure class='image-display'> + <img src="/resources/images/devguide/attribute-directives/first-highlight.png" alt="First Highlight"> </img> +</figure> + + +### Your directive isn't working? + +Did you remember to add the directive to the `declarations` attribute of `@NgModule`? It is easy to forget! +Open the console in the browser tools and look for an error like this: +<code-example format="nocode"> + EXCEPTION: Template parse errors: + Can't bind to 'myHighlight' since it isn't a known property of 'p'. + +</code-example> + +Angular detects that you're trying to bind to *something* but it can't find this directive +in the module's `declarations` array. +After specifying `HighlightDirective` in the `declarations` array, +Angular knows it can apply the directive to components declared in this module. +To summarize, Angular found the `myHighlight` attribute on the `<p>` element. +It created an instance of the `HighlightDirective` class and +injected a reference to the `<p>` element into the directive's constructor +which sets the `<p>` element's background style to yellow. + + + +{@a respond-to-user} +## Respond to user-initiated events + +Currently, `myHighlight` simply sets an element color. +The directive could be more dynamic. +It could detect when the user mouses into or out of the element +and respond by setting or clearing the highlight color. + +Begin by adding `HostListener` to the list of imported symbols; +add the `Input` symbol as well because you'll need it soon. + +{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='imports'} + +Then add two eventhandlers that respond when the mouse enters or leaves, each adorned by the `HostListener` !{_decorator}. + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='mouse-methods'} + +The `@HostListener` !{_decorator} lets you subscribe to events of the DOM element that hosts an attribute directive, the `<p>` in this case. + +Of course you could reach into the DOM with standard JavaScript and and attach event listeners manually. +There are at least three problems with _that_ approach: + +1. You have to write the listeners correctly. +1. The code must *detach* the listener when the directive is destroyed to avoid memory leaks. +1. Talking to DOM API directly isn't a best practice. +The handlers delegate to a helper method that sets the color on the DOM element, `#{_priv}el`, +which you declare and initialize in the constructor. + + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='ctor'} + +Here's the updated directive in full: + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts'} + +Run the app and confirm that the background color appears when the mouse hovers over the `p` and +disappears as it moves out. +<figure class='image-display'> + <img src="/resources/images/devguide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight"> </img> +</figure> + + + + +{@a bindings} +## Pass values into the directive with an _@Input_ data binding + +Currently the highlight color is hard-coded _within_ the directive. That's inflexible. +In this section, you give the developer the power to set the highlight color while applying the directive. + +Start by adding a `highlightColor` property to the directive class like this: + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color'} + + + +{@a input} +### Binding to an _@Input_ property + +Notice the `@Input` !{_decorator}. It adds metadata to the class that makes the directive's `highlightColor` property available for binding. + +It's called an *input* property because data flows from the binding expression _into_ the directive. +Without that input metadata, Angular rejects the binding; see [below](#why-input "Why add @Input?") for more about that. + +Try it by adding the following directive binding variations to the `AppComponent` template: + +{@example 'attribute-directives/ts/src/app/app.component.1.html' region='color-1'} + +Add a `color` property to the `AppComponent`. + +{@example 'attribute-directives/ts/src/app/app.component.1.ts' region='class'} + +Let it control the highlight color with a property binding. + +{@example 'attribute-directives/ts/src/app/app.component.1.html' region='color-2'} + +That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this. + +{@example 'attribute-directives/ts/src/app/app.component.html' region='color'} + +The `[myHighlight]` attribute binding both applies the highlighting directive to the `<p>` element +and sets the directive's highlight color with a property binding. +You're re-using the directive's attribute selector (`[myHighlight]`) to do both jobs. +That's a crisp, compact syntax. + +You'll have to rename the directive's `highlightColor` property to `myHighlight` because that's now the color property binding name. + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color-2'} + +This is disagreeable. The word, `myHighlight`, is a terrible property name and it doesn't convey the property's intent. + + +{@a input-alias} +### Bind to an _@Input_ alias + +Fortunately you can name the directive property whatever you want _and_ **_alias it_** for binding purposes. + +Restore the original property name and specify the selector as the alias in the argument to `@Input`. +_Inside_ the directive the property is known as `highlightColor`. +_Outside_ the directive, where you bind to it, it's known as `myHighlight`. + +You get the best of both worlds: the property name you want and the binding syntax you want: + +{@example 'attribute-directives/ts/src/app/app.component.html' region='color'} + +Now that you're binding to `highlightColor`, modify the `onMouseEnter()` method to use it. +If someone neglects to bind to `highlightColor`, highlight in "red" by default. + + +{@example 'attribute-directives/ts/src/app/highlight.directive.3.ts' region='mouse-enter'} + +Here's the latest version of the directive class.## Write a harness to try itIt may be difficult to imagine how this directive actually works. +In this section, you'll turn `AppComponent` into a harness that +lets you pick the highlight color with a radio button and bind your color choice to the directive. + +Update `app.component.html` as follows: +Revise the `AppComponent.color` so that it has no initial value.Here is the harness and directive in action. +<figure class='image-display'> + <img src="/resources/images/devguide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2"> </img> +</figure> + + + + +{@a second-property} +## Bind to a second property +This highlight directive has a single customizable property. In a real app, it may need more. + +At the moment, the default color—the color that prevails until +the user picks a highlight color—is hard-coded as "red". +Let the template developer set the default color. + +Add a second **input** property to `HighlightDirective` called `defaultColor`:Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`, +then with the `defaultColor`, and falls back to "red" if both properties are undefined. + +{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='mouse-enter'} + +How do you bind to a second property when you're already binding to the `myHighlight` attribute name? + +As with components, you can add as many directive property bindings as you need by stringing them along in the template. +The developer should be able to write the following template HTML to both bind to the `AppComponent.color` +and fall back to "violet" as the default color. + +{@example 'attribute-directives/ts/src/app/app.component.html' region='defaultColor'} + +Angular knows that the `defaultColor` binding belongs to the `HighlightDirective` +because you made it _public_ with the `@Input` !{_decorator}. + +Here's how the harness should work when you're done coding. +<figure class='image-display'> + <img src="/resources/images/devguide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight"> </img> +</figure> + + +## Summary +This page covered how to: +- [Build an **attribute directive**](#write-directive) that modifies the behavior of an element. +- [Apply the directive](#apply-directive) to an element in a template. +- [Respond to **events**](#respond-to-user) that change the directive's behavior. +- [**Bind** values to the directive](#bindings). + +The final source code follows: + +<md-tab-group> + + <md-tab label="app/app.component.ts"> + {@example 'attribute-directives/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="app/app.component.html"> + {@example 'attribute-directives/ts/src/app/app.component.html'} + </md-tab> + + + <md-tab label="app/highlight.directive.ts"> + {@example 'attribute-directives/ts/src/app/highlight.directive.ts'} + </md-tab> + + + <md-tab label="app/app.module.ts"> + {@example 'attribute-directives/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="main.ts"> + {@example 'attribute-directives/ts/src/main.ts'} + </md-tab> + + + <md-tab label="index.html"> + {@example 'attribute-directives/ts/src/index.html'} + </md-tab> + + +</md-tab-group> + +You can also experience and download the <live-example title="Attribute Directive example"></live-example>. + + +{@a why-input} + +### Appendix: Why add _@Input_? + +In this demo, the `hightlightColor` property is an ***input*** property of +the `HighlightDirective`. You've seen it applied without an alias: + +{@example 'attribute-directives/ts/src/app/highlight.directive.2.ts' region='color'} + +You've seen it with an alias: + +{@example 'attribute-directives/ts/src/app/highlight.directive.ts' region='color'} + +Either way, the `@Input` !{_decorator} tells Angular that this property is +_public_ and available for binding by a parent component. +Without `@Input`, Angular refuses to bind to the property. + +You've bound template HTML to component properties before and never used `@Input`. +What's different? + +The difference is a matter of trust. +Angular treats a component's template as _belonging_ to the component. +The component and its template trust each other implicitly. +Therefore, the component's own template may bind to _any_ property of that component, +with or without the `@Input` !{_decorator}. + +But a component or directive shouldn't blindly trust _other_ components and directives. +The properties of a component or directive are hidden from binding by default. +They are _private_ from an Angular binding perspective. +When adorned with the `@Input` !{_decorator}, the property becomes _public_ from an Angular binding perspective. +Only then can it be bound by some other component or directive. + +You can tell if `@Input` is needed by the position of the property name in a binding. + +* When it appears in the template expression to the ***right*** of the equals (=), +it belongs to the template's component and does not require the `@Input` !{_decorator}. + +* When it appears in **square brackets** ([ ]) to the **left** of the equals (=), +the property belongs to some _other_ component or directive; +that property must be adorned with the `@Input` !{_decorator}. + +Now apply that reasoning to the following example: + +{@example 'attribute-directives/ts/src/app/app.component.html' region='color'} + +* The `color` property in the expression on the right belongs to the template's component. +The template and its component trust each other. +The `color` property doesn't require the `@Input` !{_decorator}. + +* The `myHighlight` property on the left refers to an _aliased_ property of the `MyHighlightDirective`, +not a property of the template's component. There are trust issues. +Therefore, the directive property must carry the `@Input` !{_decorator}. \ No newline at end of file diff --git a/aio/content/guide/browser-support.md b/aio/content/guide/browser-support.md new file mode 100644 index 0000000000..b3c01ea9c4 --- /dev/null +++ b/aio/content/guide/browser-support.md @@ -0,0 +1,614 @@ +@title +Browser support + +@intro +Browser support and polyfills guide. + +@description +Angular supports most recent browsers. This includes the following specific versions: + +<table> + + <tr> + + <th> + Chrome + </th> + + + <th> + Firefox + </th> + + + <th> + Edge + </th> + + + <th> + IE + </th> + + + <th> + Safari + </th> + + + <th> + iOS + </th> + + + <th> + Android + </th> + + + <th> + IE mobile + </th> + + + </tr> + + + <tr> + + <td> + latest + </td> + + + <td> + latest + </td> + + + <td> + 14 + </td> + + + <td> + 11 + </td> + + + <td> + 10 + </td> + + + <td> + 10 + </td> + + + <td> + Marshmallow (6.0) + </td> + + + <td> + 11 + </td> + + + </tr> + + + <tr> + + <td> + + </td> + + + <td> + + </td> + + + <td> + 13 + </td> + + + <td> + 10 + </td> + + + <td> + 9 + </td> + + + <td> + 9 + </td> + + + <td> + Lollipop<br>(5.0, 5.1) + </td> + + + <td> + + </td> + + + </tr> + + + <tr> + + <td> + + </td> + + + <td> + + </td> + + + <td> + + </td> + + + <td> + 9 + </td> + + + <td> + 8 + </td> + + + <td> + 8 + </td> + + + <td> + KitKat<br>(4.4) + </td> + + + <td> + + </td> + + + </tr> + + + <tr> + + <td> + + </td> + + + <td> + + </td> + + + <td> + + </td> + + + <td> + + </td> + + + <td> + 7 + </td> + + + <td> + 7 + </td> + + + <td> + Jelly Bean<br>(4.1, 4.2, 4.3) + </td> + + + <td> + + </td> + + + </tr> + + +</table> + + +Angular's continuous integration process runs unit tests of the framework on all of these browsers for every pull request, +using <a href="https://saucelabs.com/" target="_blank">SauceLabs</a> and +<a href="https://www.browserstack.com" target="_blank">Browserstack</a>. +## Polyfills # +Angular is built on the latest standards of the web platform. +Targeting such a wide range of browsers is challenging because they do not support all features of modern browsers. + +You compensate by loading polyfill scripts ("polyfills") on the host web page (`index.html`) +that implement missing features in JavaScript. + +{@example 'quickstart/ts/src/index.html' region='polyfills'} + +A particular browser may require at least one polyfill to run _any_ Angular application. +You may need additional polyfills for specific features. + +The tables below will help you determine which polyfills to load, depending on the browsers you target and the features you use. + + +~~~ {.alert.is-important} + +The suggested polyfills are the ones we know will run full Angular applications. +You may need additional polyfills to support features not covered by this list. +Note that polyfills cannot magically transform an old, slow browser into a modern, fast one. + + +~~~ + +### Mandatory polyfills ## +These are the polyfills required to run an Angular application on each supported browser: + +<table> + + <tr style="vertical-align: top"> + + <th> + Browsers (desktop & mobile) + </th> + + + <th> + Polyfills required + </th> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + Chrome, Firefox, Edge, Safari 9+ + </td> + + + <td> + None + </td> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + Safari 7 & 8, IE10 & 11, Android 4.1+ + </td> + + + <td> + [ES6](#core-es6) + </td> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + IE9 + </td> + + + <td> + [ES6<br>classList](#classlist) + + </td> + + + </tr> + + +</table> + +### Optional browser features to polyfill ## +Some features of Angular may require additional polyfills. + +For example, the animations library relies on the standard web animation API, which is only available in Chrome and Firefox today. +You'll need a polyfill to use animations in other browsers. + +Here are the features which may require additional polyfills: + +<table> + + <tr style="vertical-align: top"> + + <th> + Feature + </th> + + + <th> + Polyfill + </th> + + + <th style="width: 50%"> + Browsers (desktop & mobile) + </th> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + <a href="./animations.html"> Animations </a> + </td> + + + <td> + [Web Animations](#web-animations) + </td> + + + <td> + All but Chrome and Firefox<br>Not supported in IE9 + </td> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + <a href="../api/common/index/DatePipe-pipe.html" target="_blank"> Date </a> <span> , </span> <a href="../api/common/index/CurrencyPipe-pipe.html" target="_blank"> currency </a> <span> , </span> <a href="../api/common/index/DecimalPipe-pipe.html" target="_blank"> decimal </a> <span> and </span> <a href="../api/common/index/PercentPipe-pipe.html" target="_blank"> percent </a> <span> pipes </span> + </td> + + + <td> + [Intl API](#intl) + </td> + + + <td> + All but Chrome, Firefox, Edge, IE11 and Safari 10 + </td> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + <a href="../api/common/index/NgClass-directive.html" target="_blank"> NgClass </a> <span> on SVG elements </span> + </td> + + + <td> + [classList](#classlist) + </td> + + + <td> + IE10, IE11 + </td> + + + </tr> + + + <tr style="vertical-align: top"> + + <td> + <a href="./server-communication.html"> Http </a> <span> when sending and receiving binary data </span> + </td> + + + <td> + [Typed Array](#typedarray) <br>[Blob](#blob)<br>[FormData](#formdata) + </td> + + + <td> + IE 9 + </td> + + + </tr> + + +</table> + +### Suggested polyfills ## +Below are the polyfills which are used to test the framework itself. They are a good starting point for an application. + +<table> + + <tr> + + <th> + Polyfill + </th> + + + <th> + Licence + </th> + + + <th> + Size* + </th> + + + </tr> + + + <tr> + + <td> + <a id='core-es6' href="https://github.com/zloirock/core-js" target="_blank"> ES6 </a> + </td> + + + <td> + MIT + </td> + + + <td> + 27.4KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='classlist' href="https://github.com/eligrey/classList.js" target="_blank"> classList </a> + </td> + + + <td> + Public domain + </td> + + + <td> + 1KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='intl' href="https://github.com/andyearnshaw/Intl.js" target="_blank"> Intl </a> + </td> + + + <td> + MIT / Unicode licence + </td> + + + <td> + 13.5KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='web-animations' href="https://github.com/web-animations/web-animations-js" target="_blank"> Web Animations </a> + </td> + + + <td> + Apache + </td> + + + <td> + 14.8KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='typedarray' href="https://github.com/inexorabletash/polyfill/blob/master/typedarray.js" target="_blank"> Typed Array </a> + </td> + + + <td> + MIT + </td> + + + <td> + 4KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='blob' href="https://github.com/eligrey/Blob.js" target="_blank"> Blob </a> + </td> + + + <td> + MIT + </td> + + + <td> + 1.3KB + </td> + + + </tr> + + + <tr> + + <td> + <a id='formdata' href="https://github.com/francois2metz/html5-formdata" target="_blank"> FormData </a> + </td> + + + <td> + MIT + </td> + + + <td> + 0.4KB + </td> + + + </tr> + + +</table> + +\* Figures are for minified and gzipped code, computed with the <a href="http://closure-compiler.appspot.com/home" target="_blank">closure compiler</a> \ No newline at end of file diff --git a/aio/content/guide/change-log.md b/aio/content/guide/change-log.md new file mode 100644 index 0000000000..1fc50ab574 --- /dev/null +++ b/aio/content/guide/change-log.md @@ -0,0 +1,187 @@ +@title +Change Log + +@intro +An annotated history of recent documentation improvements. + +@description +The Angular documentation is a living document with continuous improvements. +This log calls attention to recent significant changes. + +## Template Syntax/Structural Directives: refreshed (2017-02-06) +The [_Template-Syntax_](template-syntax.html) and [_Structural Directives_](structural-directives.html) +guides were significantly revised for clarity, accuracy, and current recommended practices. +Discusses `<ng-container>`. +Revised samples are more clear and cover all topics discussed. + +## NEW: Samples re-structured with `src/` folder (2017-02-02) +All documentation samples have been realigned with the default folder structure of the angular-cli. +That's a step along the road to basing our sample in the angular-cli. +But it's also good in its own right. +It helps clearly separate app code from setup and configuration files. + +We've updated all samples with an `src/` folder at the project root. +The former `app/` folder moves under `src/`. +Read about moving your existing project to this structure in +<a href="https://github.com/angular/quickstart#updating-to-a-newer-version-of-the-quickstart-repo" target="_blank" target="Migrating samples/quickstart app to the src folder"> +the QuickStart repo update instructions</a>. + +Notably: +* `app/main.ts` moved to `src/main.ts`. +* `app/` moved to `src/app/`. +* `index.html`, `styles.css` and `tsconfig.json` moved inside `src/`. +* `systemjs.config.js` now imports `main.js` instead of `app`. +* Added `lite-server` configuration (`bs-config.json`) to serve `src/`. + +## NEW: Reactive Forms guide (2017-01-31) +The new [**Reactive Forms**](reactive-forms.html) guide explains how and why to build a "reactive form". +"Reactive Forms" are the code-based counterpart to the declarative "Template Driven" forms approach +introduced in the [Forms](forms.html) guide. +Check it out before you decide how to add forms to your app. +Remember also that you can use both techniques in the same app, +choosing the approach that best fits each scenario. + +## NEW: Deployment guide (2017-01-30) +The new [Deployment](deployment.html) guide describes techniques for putting your application on a server. +It includes important advice on optimizing for production. + +## Hierarchical Dependency Injection: refreshed (2017-01-13) +[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) guide significantly revised. +Closes issue #3086 +Revised samples are more clear and cover all topics discussed. + +## Miscellaneous (2017-01-05) +* [Setup](setup.html) guide: +added (optional) instructions on how to remove _non-essential_ files. +* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs. +* All samples prepend template/style URLS URLs w/ `./` ... and so should you. +* [Style Guide](style-guide.html): copy edits and revised rules. + +## Router: more detail (2016-12-21) +Added more information to the [Router](router.html) guide +including sections named outlets, wildcard routes, and preload strategies. + +## Http: how to set default request headers (and other request options) (2016-12-14) +Added section on how to set default request headers (and other request options) to +[Http](server-communication.html#override-default-request-options) guide. + +## Testing: added component test plunkers (2016-12-02) +Added two plunkers that each test _one simple component_ so you can write a component test plunker of your own: <live-example name="setup" plnkr="quickstart-specs">one</live-example> for the QuickStart seed's `AppComponent` and <live-example name="testing" plnkr="banner-specs">another</live-example> for the Testing guide's `BannerComponent`. +Linked to these plunkers in [Testing](testing.html#live-examples) and [Setup anatomy](setup-systemjs-anatomy) guides. + +## Internationalization: pluralization and _select_ (2016-11-30) +The [Internationalization (i18n)](../cookbook/i18n.html) guide explains how to handle pluralization and +translation of alternative texts with `select`. +The sample demonstrates these features too. + +## Testing: karma file updates (2016-11-30) +* karma.config + karma-test-shim can handle multiple spec source paths; +see quickstart issue: [angular/quickstart#294](https://github.com/angular/quickstart/issues/294) +* Displays Jasmine Runner output in the karma-launched browser + +## QuickStart Rewrite (2016-11-18) +The QuickStart is completely rewritten so that it actually is quick. +It references a minimal "Hello Angular" app running in Plunker. +The new [Setup](setup.html) page tells you how to install a local development environment +by downloading (or cloning) the QuickStart github repository. +You are no longer asked to copy-and-paste code into setup files that were not explained anyway. + +## Sync with Angular v.2.2.0 (2016-11-14) +Docs and code samples updated and tested with Angular v.2.2.0 + +## UPDATE: NgUpgrade Guide for the AOT friendly _upgrade/static_ module (2016-11-14) +The updated [NgUpgrade Guide](upgrade.html) guide covers the +new AOT friendly `upgrade/static` module +released in v.2.2.0, which is the recommended +facility for migrating from AngularJS to Angular. +The documentation for the version prior to v.2.2.0 has been removed. + +## ES6 described in "TypeScript to JavaScript" (2016-11-14) +The updated "[TypeScript to JavaScript](../cookbook/ts-to-js.html)" cookbook +now explains how to write apps in ES6/7 +by translating the common idioms in the TypeScript documentation examples +(and elsewhere on the web) to ES6/7 and ES5. + +## Sync with Angular v.2.1.1 (2016-10-21) +Docs and code samples updated and tested with Angular v.2.1.0 + +## npm _@types_ packages replace _typings_ (2016-10-20) +Documentation samples now get TypeScript type information for 3rd party libraries +from npm `@types` packages rather than with the _typings_ tooling. +The `typings.json` file is gone. + +The "[AngularJS Upgrade](upgrade.html)" guide reflects this change. +The `package.json` installs `@types/angular` and several `@types/angular-...` +packages in support of upgrade; these are not needed for pure Angular development. + +## "Template Syntax" explains two-way data binding syntax (2016-10-20) +Demonstrates how to two-way data bind to a custom Angular component and +re-explains `[(ngModel)]` in terms of the basic `[()]` syntax. + +## BREAKING CHANGE: `in-memory-web-api` (v.0.1.11) delivered as esm umd (2016-10-19) +This change supports ES6 developers and aligns better with typical Angular libraries. +It does not affect the module's API but it does affect how you load and import it. +See the <a href="https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md#0113-2016-10-20" target="_blank">change note</a> +in the `in-memory-web-api` repo. + +## "Router" _preload_ syntax and _:enter_/_:leave_ animations (2016-10-19) +The router can lazily _preload_ modules _after_ the app starts and +_before_ the user navigates to them for improved perceived performance. + +New `:enter` and `:leave` aliases make animation more natural. + +## Sync with Angular v.2.1.0 (2016-10-12) +Docs and code samples updated and tested with Angular v.2.1.0 + +## NEW "Ahead of time (AOT) Compilation" cookbook (2016-10-11) +The NEW [Ahead of time (AOT) Compilation](../cookbook/aot-compiler.html) cookbook +explains what AOT compilation is and why you'd want it. +It demonstrates the basics with a QuickStart app +followed by the more advanced considerations of compiling and bundling the Tour of Heroes. + +## Sync with Angular v.2.0.2 (2016-10-6) +Docs and code samples updated and tested with Angular v.2.0.2 + +## "Routing and Navigation" guide with the _Router Module_ (2016-10-5) +The [Routing and Navigation](router.html) guide now locates route configuration +in a _Routing Module_. +The _Routing Module_ replaces the previous _routing object_ involving the `ModuleWithProviders`. + +All guided samples with routing use the _Routing Module_ and prose content has been updated, +most conspicuously in the +[NgModule](ngmodule.html) guide and [NgModule FAQ](../cookbook/ngmodule-faq.html) cookbook. + +## New "Internationalization" Cookbook (2016-09-30) + +Added a new [Internationalization (i18n)](../cookbook/i18n.html) cookbook that shows how +to use Angular "i18n" facilities to translate template text into multiple languages. + +## "angular-in-memory-web-api" package rename (2016-09-27) + +Many samples use the `angular-in-memory-web-api` to simulate a remote server. +This library is also useful to you during early development before you have a server to talk to. + +The package name was changed from "angular2-in-memory-web-api" which is still frozen-in-time on npm. +The new "angular-in-memory-web-api" has new features. +<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md" target="_blank">Read about them on github</a>. + +## "Style Guide" with _NgModules_ (2016-09-27) + +[StyleGuide](style-guide.html) explains our recommended conventions for Angular modules (NgModule). +Barrels now are far less useful and have been removed from the style guide; +they remain valuable but are not a matter of Angular style. +We also relaxed the rule that discouraged use of the `@Component.host` property. + +## _moduleId: module.id_ everywhere (2016-09-25) + +Sample components that get their templates or styles with `templateUrl` or `styleUrls` +have been converted to _module-relative_ URLs. +We added the `moduleId: module.id` property-and-value to their `@Component` metadata. + +This change is a requirement for compilation with AOT compiler when the app loads +modules with SystemJS as the samples currently do. + +## "Lifecycle Hooks" guide simplified (2016-09-24) + +The [Lifecycle Hooks](lifecycle-hooks.html) guide is shorter, simpler, and +draws more attention to the order in which Angular calls the hooks. \ No newline at end of file diff --git a/aio/content/guide/cheatsheet.md b/aio/content/guide/cheatsheet.md new file mode 100644 index 0000000000..27a61dff26 --- /dev/null +++ b/aio/content/guide/cheatsheet.md @@ -0,0 +1,3 @@ +@title +Cheat Sheet + diff --git a/aio/content/guide/component-styles.md b/aio/content/guide/component-styles.md new file mode 100644 index 0000000000..fa0063e9f5 --- /dev/null +++ b/aio/content/guide/component-styles.md @@ -0,0 +1,291 @@ +@title +Component Styles + +@intro +Learn how to apply CSS styles to components. + +@description +Angular applications are styled with regular CSS. That means we can apply +everything we know about CSS stylesheets, selectors, rules, and media queries +to our Angular applications directly. + +On top of this, Angular has the ability to bundle *component styles* +with our components enabling a more modular design than regular stylesheets. + +In this chapter we learn how to load and apply these *component styles*. + +## Table Of Contents + +* [Using Component Styles](#using-component-styles) +* [Special selectors](#special-selectors) +* [Loading Styles into Components](#loading-styles) +* [Controlling View Encapsulation: Emulated, Native, and None](#view-encapsulation) +* [Appendix 1: Inspecting the generated runtime component styles](#inspect-generated-css) +* [Appendix 2: Loading Styles with Relative URLs](#relative-urls) + +Run the <live-example></live-example> of the code shown in this chapter. + +## Using Component Styles + +For every Angular component we write, we may define not only an HTML template, +but also the CSS styles that go with that template, +specifying any selectors, rules, and media queries that we need. + +One way to do this is to set the `styles` property in the component metadata. +The `styles` property takes #{_an} #{_array} of strings that contain CSS code. +Usually we give it one string as in this example: + + +{@example 'component-styles/ts/src/app/hero-app.component.ts'} + +Component styles differ from traditional, global styles in a couple of ways. + +Firstly, the selectors we put into a component's styles *only apply within the template +of that component*. The `h1` selector in the example above only applies to the `<h1>` tag +in the template of `HeroAppComponent`. Any `<h1>` elements elsewhere in +the application are unaffected. + +This is a big improvement in modularity compared to how CSS traditionally works: + +1. We can use the CSS class names and selectors that make the most sense in the context of each component. + +1. Class names and selectors are local to the component and won't collide with +classes and selectors used elsewhere in the application. + +1. Our component's styles *cannot* be changed by changes to styles elsewhere in the application. + +1. We can co-locate the CSS code of each component with the TypeScript and HTML code of the component, + which leads to a neat and tidy project structure. + +1. We can change or remove component CSS code in the future without trawling through the + whole application to see where else it may have been used. We just look at the component we're in. + + +{@a special-selectors} + +## Special selectors + +Component styles have a few special *selectors* from the world of +[shadow DOM style scoping](https://www.w3.org/TR/css-scoping-1): + +### :host + +Use the `:host` pseudo-class selector to target styles in the element that *hosts* the component (as opposed to +targeting elements *inside* the component's template): + + +{@example 'component-styles/ts/src/app/hero-details.component.css' region='host'} + +This is the *only* way we can target the host element. We cannot reach +it from inside the component with other selectors, because it is not part of the +component's own template. It is in a parent component's template. + +Use the *function form* to apply host styles conditionally by +including another selector inside parentheses after `:host`. + +In the next example we target the host element again, but only when it also has the `active` CSS class. + + +{@example 'component-styles/ts/src/app/hero-details.component.css' region='hostfunction'} + +### :host-context + +Sometimes it is useful to apply styles based on some condition *outside* a component's view. +For example, there may be a CSS theme class applied to the document `<body>` element, and +we want to change how our component looks based on that. + +Use the `:host-context()` pseudo-class selector. It works just like the function +form of `:host()`. It looks for a CSS class in *any ancestor* of the component host element, all the way +up to the document root. It's useful when combined with another selector. + +In the following example, we apply a `background-color` style to all `<h2>` elements *inside* the component, only +if some ancestor element has the CSS class `theme-light`. + + +{@example 'component-styles/ts/src/app/hero-details.component.css' region='hostcontext'} + +### /deep/ + +Component styles normally apply only to the HTML in the component's own template. + +We can use the `/deep/` selector to force a style down through the child component tree into all the child component views. +The `/deep/` selector works to any depth of nested components, and it applies *both to the view +children and the content children* of the component. + +In this example, we target all `<h3>` elements, from the host element down +through this component to all of its child elements in the DOM: + +{@example 'component-styles/ts/src/app/hero-details.component.css' region='deep'} + +The `/deep/` selector also has the alias `>>>`. We can use either of the two interchangeably. + + +~~~ {.alert.is-important} + +The `/deep/` and `>>>` selectors should only be used with **emulated** view encapsulation. +This is the default and it is what we use most of the time. See the +[Controlling View Encapsulation](#view-encapsulation) +section for more details. + + +~~~ + + + +{@a loading-styles} + +## Loading Styles into Components + +We have several ways to add styles to a component: +* inline in the template HTML +* by setting `styles` or `styleUrls` metadata +* with CSS imports + +The scoping rules outlined above apply to each of these loading patterns. + +### Styles in Metadata + +We can add a `styles` #{_array} property to the `@Component` #{_decorator}. +Each string in the #{_array} (usually just one string) defines the CSS. + + +{@example 'component-styles/ts/src/app/hero-app.component.ts'} + +### Template Inline Styles + +We can embed styles directly into the HTML template by putting them +inside `<style>` tags. + + +{@example 'component-styles/ts/src/app/hero-controls.component.ts' region='inlinestyles'} + +### Style URLs in Metadata + +We can load styles from external CSS files by adding a `styleUrls` attribute +into a component's `@Component` #{_decorator}: + + +{@example 'component-styles/ts/src/app/hero-details.component.ts' region='styleurls'} + +### Template Link Tags + +We can also embed `<link>` tags into the component's HTML template. + +As with `styleUrls`, the link tag's `href` URL is relative to the +application root, not relative to the component file. + + +{@example 'component-styles/ts/src/app/hero-team.component.ts' region='stylelink'} + +### CSS @imports + +We can also import CSS files into our CSS files by using the standard CSS +[`@import` rule](https://developer.mozilla.org/en/docs/Web/CSS/@import). + + +{@example 'component-styles/ts/src/app/hero-details.component.css' region='import'} + + + +{@a view-encapsulation} + +## Controlling View Encapsulation: Native, Emulated, and None + +As discussed above, component CSS styles are *encapsulated* into the component's own view and do +not affect the rest of the application. + +We can control how this encapsulation happens on a *per +component* basis by setting the *view encapsulation mode* in the component metadata. There +are three modes to choose from: + +* `Native` view encapsulation uses the browser's native [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM) + implementation to attach a Shadow DOM to the component's host element, and then puts the component + view inside that Shadow DOM. The component's styles are included within the Shadow DOM. + +* `Emulated` view encapsulation (**the default**) emulates the behavior of Shadow DOM by preprocessing + (and renaming) the CSS code to effectively scope the CSS to the component's view. + See [Appendix 1](#inspect-generated-css) for details. + +* `None` means that Angular does no view encapsulation. + Angular adds the CSS to the global styles. + The scoping rules, isolations, and protections discussed earlier do not apply. + This is essentially the same as pasting the component's styles into the HTML. + +Set the components encapsulation mode using the `encapsulation` property in the component metadata: + + +{@example 'component-styles/ts/src/app/quest-summary.component.ts' region='encapsulation.native'} + +`Native` view encapsulation only works on [browsers that have native support +for Shadow DOM](http://caniuse.com/#feat=shadowdom). The support is still limited, +which is why `Emulated` view encapsulation is the default mode and recommended +in most cases. + + +{@a inspect-generated-css} + +## Appendix 1: Inspecting The CSS Generated in Emulated View Encapsulation + +When using the default emulated view encapsulation, Angular preprocesses +all component styles so that they approximate the standard Shadow CSS scoping rules. + +When we inspect the DOM of a running Angular application with emulated view +encapsulation enabled, we see that each DOM element has some extra attributes +attached to it: + +<code-example format=""> + <hero-details _nghost-pmm-5> + <h2 _ngcontent-pmm-5>Mister Fantastic</h2> + <hero-team _ngcontent-pmm-5 _nghost-pmm-6> + <h3 _ngcontent-pmm-6>Team</h3> + </hero-team> + </hero-detail> + +</code-example> + +We see two kinds of generated attributes: +* An element that would be a Shadow DOM host in native encapsulation has a + generated `_nghost` attribute. This is typically the case for component host elements. + +* An element within a component's view has a `_ngcontent` attribute +that identifies to which host's emulated Shadow DOM this element belongs. + +The exact values of these attributes are not important. They are automatically +generated and we never refer to them in application code. But they are targeted +by the generated component styles, which we'll find in the `<head>` section of the DOM: + +<code-example format=""> + [_nghost-pmm-5] { + display: block; + border: 1px solid black; + } + + h3[_ngcontent-pmm-6] { + background-color: white; + border: 1px solid #777; + } + +</code-example> + +These are the styles we wrote, post-processed so that each selector is augmented +with `_nghost` or `_ngcontent` attribute selectors. +These extra selectors enable the scoping rules described in this guide. + +We'll likely live with *emulated* mode until shadow DOM gains traction. + + +{@a relative-urls} + +## Appendix 2: Loading Styles with Relative URLs + +It's common practice to split a component's code, HTML, and CSS into three separate files in the same directory: +<code-example format="nocode"> + quest-summary.component.ts + quest-summary.component.html + quest-summary.component.css + +</code-example> + +We include the template and CSS files by setting the `templateUrl` and `styleUrls` metadata properties respectively. +Because these files are co-located with the component, +it would be nice to refer to them by name without also having to specify a path back to the root of the application. diff --git a/aio/content/guide/dependency-injection.md b/aio/content/guide/dependency-injection.md new file mode 100644 index 0000000000..2f9444e53d --- /dev/null +++ b/aio/content/guide/dependency-injection.md @@ -0,0 +1,737 @@ +@title +Dependency Injection + +@intro +Angular's dependency injection system creates and delivers dependent services "just-in-time". + +@description +**Dependency injection** is an important application design pattern. +Angular has its own dependency injection framework, and +we really can't build an Angular application without it. +It's used so widely that almost everyone just calls it _DI_. + +In this chapter we'll learn what DI is and why we want it. +Then we'll learn [how to use it](#angular-di) in an Angular app. + +- [Why dependency injection?](#why-dependency-injection) +- [Angular dependency injection](#angular-dependency-injection) +- [Injector providers](#injector-providers) +- [Dependency injection tokens](#dependency-injection-tokens) +- [Summary](#summary) + +Run the <live-example></live-example>. + +## Why dependency injection? + +Let's start with the following code. + + +{@example 'dependency-injection/ts/src/app/car/car-no-di.ts' region='car'} + +Our `Car` creates everything it needs inside its constructor. +What's the problem? +The problem is that our `Car` class is brittle, inflexible, and hard to test. + +Our `Car` needs an engine and tires. Instead of asking for them, +the `Car` constructor instantiates its own copies from +the very specific classes `Engine` and `Tires`. + +What if the `Engine` class evolves and its constructor requires a parameter? +Our `Car` is broken and stays broken until we rewrite it along the lines of +`#{_thisDot}engine = new Engine(theNewParameter)`. +We didn't care about `Engine` constructor parameters when we first wrote `Car`. +We don't really care about them now. +But we'll *have* to start caring because +when the definition of `Engine` changes, our `Car` class must change. +That makes `Car` brittle. + +What if we want to put a different brand of tires on our `Car`? Too bad. +We're locked into whatever brand the `Tires` class creates. That makes our `Car` inflexible. + +Right now each new car gets its own engine. It can't share an engine with other cars. +While that makes sense for an automobile engine, +we can think of other dependencies that should be shared, such as the onboard +wireless connection to the manufacturer's service center. Our `Car` lacks the flexibility +to share services that have been created previously for other consumers. + +When we write tests for our `Car` we're at the mercy of its hidden dependencies. +Is it even possible to create a new `Engine` in a test environment? +What does `Engine`itself depend upon? What does that dependency depend on? +Will a new instance of `Engine` make an asynchronous call to the server? +We certainly don't want that going on during our tests. + +What if our `Car` should flash a warning signal when tire pressure is low? +How do we confirm that it actually does flash a warning +if we can't swap in low-pressure tires during the test? + +We have no control over the car's hidden dependencies. +When we can't control the dependencies, a class becomes difficult to test. + +How can we make `Car` more robust, flexible, and testable? + +<a id="ctor-injection"></a> +That's super easy. We change our `Car` constructor to a version with DI: + +<md-tab-group> + + <md-tab label="src/app/car/car.ts (excerpt with DI)"> + {@example 'dependency-injection/ts/src/app/car/car.ts' region='car-ctor'} + </md-tab> + + + <md-tab label="src/app/car/car.ts (excerpt without DI)"> + {@example 'dependency-injection/ts/src/app/car/car-no-di.ts' region='car-ctor'} + </md-tab> + + +</md-tab-group> + +See what happened? We moved the definition of the dependencies to the constructor. +Our `Car` class no longer creates an engine or tires. +It just consumes them. +Now we create a car by passing the engine and tires to the constructor. + + +{@example 'dependency-injection/ts/src/app/car/car-creations.ts' region='car-ctor-instantiation'} + +How cool is that? +The definition of the engine and tire dependencies are +decoupled from the `Car` class itself. +We can pass in any kind of engine or tires we like, as long as they +conform to the general API requirements of an engine or tires. + +If someone extends the `Engine` class, that is not `Car`'s problem. + +The _consumer_ of `Car` has the problem. The consumer must update the car creation code to +something like this: + + +{@example 'dependency-injection/ts/src/app/car/car-creations.ts' region='car-ctor-instantiation-with-param'} + +The critical point is this: `Car` itself did not have to change. +We'll take care of the consumer's problem soon enough. +The `Car` class is much easier to test because we are in complete control +of its dependencies. +We can pass mocks to the constructor that do exactly what we want them to do +during each test: + + +{@example 'dependency-injection/ts/src/app/car/car-creations.ts' region='car-ctor-instantiation-with-mocks'} + +**We just learned what dependency injection is**. + +It's a coding pattern in which a class receives its dependencies from external +sources rather than creating them itself. + +Cool! But what about that poor consumer? +Anyone who wants a `Car` must now +create all three parts: the `Car`, `Engine`, and `Tires`. +The `Car` class shed its problems at the consumer's expense. +We need something that takes care of assembling these parts for us. + +We could write a giant class to do that: + + +{@example 'dependency-injection/ts/src/app/car/car-factory.ts'} + +It's not so bad now with only three creation methods. +But maintaining it will be hairy as the application grows. +This factory is going to become a huge spiderweb of +interdependent factory methods! + +Wouldn't it be nice if we could simply list the things we want to build without +having to define which dependency gets injected into what? + +This is where the dependency injection framework comes into play. +Imagine the framework had something called an _injector_. +We register some classes with this injector, and it figures out how to create them. + +When we need a `Car`, we simply ask the injector to get it for us and we're good to go. + + +{@example 'dependency-injection/ts/src/app/car/car-injector.ts' region='injector-call'} + +Everyone wins. The `Car` knows nothing about creating an `Engine` or `Tires`. +The consumer knows nothing about creating a `Car`. +We don't have a gigantic factory class to maintain. +Both `Car` and consumer simply ask for what they need and the injector delivers. + +This is what a **dependency injection framework** is all about. + +Now that we know what dependency injection is and appreciate its benefits, +let's see how it is implemented in Angular. + +## Angular dependency injection + +Angular ships with its own dependency injection framework. This framework can also be used +as a standalone module by other applications and frameworks. + +That sounds nice. What does it do for us when building components in Angular? +Let's see, one step at a time. + +We'll begin with a simplified version of the `HeroesComponent` +that we built in the [The Tour of Heroes](../tutorial/). + +<md-tab-group> + + <md-tab label="src/app/heroes/heroes.component.ts"> + {@example 'dependency-injection/ts/src/app/heroes/heroes.component.1.ts' region='v1'} + </md-tab> + + + <md-tab label="src/app/heroes/hero-list.component.ts"> + {@example 'dependency-injection/ts/src/app/heroes/hero-list.component.1.ts'} + </md-tab> + + + <md-tab label="src/app/heroes/hero.ts"> + {@example 'dependency-injection/ts/src/app/heroes/hero.ts'} + </md-tab> + + + <md-tab label="src/app/heroes/mock-heroes.ts"> + {@example 'dependency-injection/ts/src/app/heroes/mock-heroes.ts'} + </md-tab> + + +</md-tab-group> + +The `HeroesComponent` is the root component of the *Heroes* feature area. +It governs all the child components of this area. +Our stripped down version has only one child, `HeroListComponent`, +which displays a list of heroes. +Right now `HeroListComponent` gets heroes from `HEROES`, an in-memory collection +defined in another file. +That may suffice in the early stages of development, but it's far from ideal. +As soon as we try to test this component or want to get our heroes data from a remote server, +we'll have to change the implementation of `heroes` and +fix every other use of the `HEROES` mock data. + +Let's make a service that hides how we get hero data. + +Given that the service is a +[separate concern](https://en.wikipedia.org/wiki/Separation_of_concerns), +we suggest that you +write the service code in its own file. + +{@example 'dependency-injection/ts/src/app/heroes/hero.service.1.ts'} + +Our `HeroService` exposes a `getHeroes` method that returns +the same mock data as before, but none of its consumers need to know that. +Notice the `@Injectable()` #{_decorator} above the service class. +We'll discuss its purpose [shortly](#injectable). + +We aren't even pretending this is a real service. +If we were actually getting data from a remote server, the API would have to be +asynchronous, #{_perhaps} returning a !{_PromiseLinked}. +We'd also have to rewrite the way components consume our service. +This is important in general, but not to our current story. +A service is nothing more than a class in Angular. +It remains nothing more than a class until we register it with an Angular injector. + +<div id='bootstrap'> + +</div> + +### Configuring the injector + +We don't have to create an Angular injector. +Angular creates an application-wide injector for us during the bootstrap process. +We do have to configure the injector by registering the **providers** +that create the services our application requires. +We'll explain what [providers](#providers) are later in this chapter. +### Registering providers in a component + +Here's a revised `HeroesComponent` that registers the `HeroService`. + + +{@example 'dependency-injection/ts/src/app/heroes/heroes.component.1.ts' region='full'} + +### Preparing the HeroListComponent for injection + +The `HeroListComponent` should get heroes from the injected `HeroService`. +Per the dependency injection pattern, the component must ask for the service in its +constructor, [as we explained earlier](#ctor-injection). +It's a small change: + +<md-tab-group> + + <md-tab label="src/app/heroes/hero-list.component (with DI)"> + {@example 'dependency-injection/ts/src/app/heroes/hero-list.component.2.ts'} + </md-tab> + + + <md-tab label="src/app/heroes/hero-list.component (without DI)"> + {@example 'dependency-injection/ts/src/app/heroes/hero-list.component.1.ts'} + </md-tab> + + +</md-tab-group> + + +#### Focus on the constructor + +Adding a parameter to the constructor isn't all that's happening here. + + +{@example 'dependency-injection/ts/src/app/heroes/hero-list.component.2.ts' region='ctor'} + +Note that the constructor parameter has the type `HeroService`, and that +the `HeroListComponent` class has an `@Component` #{_decorator} +(scroll up to confirm that fact). +Also recall that the parent component (`HeroesComponent`) +has `providers` information for `HeroService`. + +The constructor parameter type, the `@Component` #{_decorator}, +and the parent's `providers` information combine to tell the +Angular injector to inject an instance of +`HeroService` whenever it creates a new `HeroListComponent`. + +<div id='di-metadata'> + +</div> + +### Implicit injector creation + +When we introduced the idea of an injector above, we showed how to +use it to create a new `Car`. Here we also show how such an injector +would be explicitly created: + + +{@example 'dependency-injection/ts/src/app/car/car-injector.ts' region='injector-create-and-call'} + +We won't find code like that in the Tour of Heroes or any of our other samples. +We *could* write code that [explicitly creates an injector](#explicit-injector) if we *had* to, but we rarely do. +Angular takes care of creating and calling injectors +when it creates components for us — whether through HTML markup, as in `<hero-list></hero-list>`, +or after navigating to a component with the [router](./router.html). +If we let Angular do its job, we'll enjoy the benefits of automated dependency injection. +### Singleton services + +Dependencies are singletons within the scope of an injector. +In our example, a single `HeroService` instance is shared among the +`HeroesComponent` and its `HeroListComponent` children. + +However, Angular DI is an hierarchical injection +system, which means that nested injectors can create their own service instances. +Learn more about that in the [Hierarchical Injectors](./hierarchical-dependency-injection.html) chapter. +### Testing the component + +We emphasized earlier that designing a class for dependency injection makes the class easier to test. +Listing dependencies as constructor parameters may be all we need to test application parts effectively. + +For example, we can create a new `HeroListComponent` with a mock service that we can manipulate +under test: + + +{@example 'dependency-injection/ts/src/app/test.component.ts' region='spec'} + + +Learn more in [Testing](./testing.html). +### When the service needs a service + +Our `HeroService` is very simple. It doesn't have any dependencies of its own. + + +What if it had a dependency? What if it reported its activities through a logging service? +We'd apply the same *constructor injection* pattern, +adding a constructor that takes a `Logger` parameter. + +Here is the revision compared to the original. + +<md-tab-group> + + <md-tab label="src/app/heroes/hero.service (v2)"> + {@example 'dependency-injection/ts/src/app/heroes/hero.service.2.ts'} + </md-tab> + + + <md-tab label="src/app/heroes/hero.service (v1)"> + {@example 'dependency-injection/ts/src/app/heroes/hero.service.1.ts'} + </md-tab> + + +</md-tab-group> + +The constructor now asks for an injected instance of a `Logger` and stores it in a private property called `#{_priv}logger`. +We call that property within our `getHeroes` method when anyone asks for heroes. + +<h3 id='injectable'> + Why @Injectable()? +</h3> + +**<a href="#{injUrl}">@Injectable()</a>** marks a class as available to an +injector for instantiation. Generally speaking, an injector will report an +error when trying to instantiate a class that is not marked as +`@Injectable()`. +Injectors are also responsible for instantiating components +like `HeroesComponent`. Why haven't we marked `HeroesComponent` as +`@Injectable()`? + +We *can* add it if we really want to. It isn't necessary because the +`HeroesComponent` is already marked with `@Component`, and this +!{_decorator} class (like `@Directive` and `@Pipe`, which we'll learn about later) +is a subtype of <a href="#{injUrl}">Injectable</a>. It is in +fact `Injectable` #{_decorator}s that +identify a class as a target for instantiation by an injector. + + +~~~ {.callout.is-critical} + + +<header> + Always include the parentheses +</header> + + + +~~~ + + +## Creating and registering a logger service + +We're injecting a logger into our `HeroService` in two steps: +1. Create the logger service. +1. Register it with the application. + +Our logger service is quite simple: + + +{@example 'dependency-injection/ts/src/app/logger.service.ts'} + +We're likely to need the same logger service everywhere in our application, +so we put it in the project's `#{_appDir}` folder, and +we register it in the `providers` #{_array} of our application !{_moduleVsComp}, `!{_AppModuleVsAppComp}`. +If we forget to register the logger, Angular throws an exception when it first looks for the logger: +<code-example format="nocode"> + EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger) + +</code-example> + +That's Angular telling us that the dependency injector couldn't find the *provider* for the logger. +It needed that provider to create a `Logger` to inject into a new +`HeroService`, which it needed to +create and inject into a new `HeroListComponent`. + +The chain of creations started with the `Logger` provider. *Providers* are the subject of our next section. + +## Injector providers + +A provider *provides* the concrete, runtime version of a dependency value. +The injector relies on **providers** to create instances of the services +that the injector injects into components and other services. + +We must register a service *provider* with the injector, or it won't know how to create the service. + +Earlier we registered the `Logger` service in the `providers` #{_array} of the metadata for the `AppModule` like this: + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-logger'} + +There are many ways to *provide* something that #{implements} `Logger`. +The `Logger` class itself is an obvious and natural provider. +But it's not the only way. + +We can configure the injector with alternative providers that can deliver #{objectlike} a `Logger`. +We could provide a substitute class. #{loggerlike} +We could give it a provider that calls a logger factory function. +Any of these approaches might be a good choice under the right circumstances. + +What matters is that the injector has a provider to go to when it needs a `Logger`. + +<div id='provide'> + +</div> + +### The *Provider* class !{_andProvideFn} +We wrote the `providers` #{_array} like this: + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-1'} + + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-3'} + +The first is the [token](#token) that serves as the key for both locating a dependency value +and registering the provider. + +The second is a !{_secondParam}, +which we can think of as a *recipe* for creating the dependency value. +There are many ways to create dependency values ... and many ways to write a recipe. + +<div id='class-provider'> + +</div> + +### Alternative class providers + +Occasionally we'll ask a different class to provide the service. +The following code tells the injector +to return a `BetterLogger` when something asks for the `Logger`. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-4'} + +### Class provider with dependencies +Maybe an `EvenBetterLogger` could display the user name in the log message. +This logger gets the user from the injected `UserService`, +which happens also to be injected at the application level. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='EvenBetterLogger'} + +Configure it like we did `BetterLogger`. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-5'} + +### Aliased class providers + +Suppose an old component depends upon an `OldLogger` class. +`OldLogger` has the same interface as the `NewLogger`, but for some reason +we can't update the old component to use it. + +When the *old* component logs a message with `OldLogger`, +we want the singleton instance of `NewLogger` to handle it instead. + +The dependency injector should inject that singleton instance +when a component asks for either the new or the old logger. +The `OldLogger` should be an alias for `NewLogger`. + +We certainly do not want two different `NewLogger` instances in our app. +Unfortunately, that's what we get if we try to alias `OldLogger` to `NewLogger` with `useClass`. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-6a'} + +The solution: alias with the `useExisting` option. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-6b'} + + +<div id='value-provider'> + +</div> + +### Value providers +Sometimes it's easier to provide a ready-made object rather than ask the injector to create it from a class. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='silent-logger'} + +Then we register a provider with the `useValue` option, +which makes this object play the logger role. + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-7'} + +See more `useValue` examples in the +[Non-class dependencies](#non-class-dependencies) and +[OpaqueToken](#opaquetoken) sections. + +<div id='factory-provider'> + +</div> + +### Factory providers + +Sometimes we need to create the dependent value dynamically, +based on information we won't have until the last possible moment. +Maybe the information changes repeatedly in the course of the browser session. + +Suppose also that the injectable service has no independent access to the source of this information. + +This situation calls for a **factory provider**. + +Let's illustrate by adding a new business requirement: +the HeroService must hide *secret* heroes from normal users. +Only authorized users should see secret heroes. + +Like the `EvenBetterLogger`, the `HeroService` needs a fact about the user. +It needs to know if the user is authorized to see secret heroes. +That authorization can change during the course of a single application session, +as when we log in a different user. + +Unlike `EvenBetterLogger`, we can't inject the `UserService` into the `HeroService`. +The `HeroService` won't have direct access to the user information to decide +who is authorized and who is not. + +Why? We don't know either. Stuff like this happens. +Instead the `HeroService` constructor takes a boolean flag to control display of secret heroes. + + +{@example 'dependency-injection/ts/src/app/heroes/hero.service.ts' region='internals'} + +We can inject the `Logger`, but we can't inject the boolean `isAuthorized`. +We'll have to take over the creation of new instances of this `HeroService` with a factory provider. + +A factory provider needs a factory function: + + +{@example 'dependency-injection/ts/src/app/heroes/hero.service.provider.ts' region='factory'} + +Although the `HeroService` has no access to the `UserService`, our factory function does. + +We inject both the `Logger` and the `UserService` into the factory provider and let the injector pass them along to the factory function: + + +{@example 'dependency-injection/ts/src/app/heroes/hero.service.provider.ts' region='provider'} + + +The `useFactory` field tells Angular that the provider is a factory function +whose implementation is the `heroServiceFactory`. + +The `deps` property is #{_an} #{_array} of [provider tokens](#token). +The `Logger` and `UserService` classes serve as tokens for their own class providers. +The injector resolves these tokens and injects the corresponding services into the matching factory function parameters. +Notice that we captured the factory provider in #{_an} #{exportedvar}, `heroServiceProvider`. +This extra step makes the factory provider reusable. +We can register our `HeroService` with this #{variable} wherever we need it. + +In our sample, we need it only in the `HeroesComponent`, +where it replaces the previous `HeroService` registration in the metadata `providers` #{_array}. +Here we see the new and the old implementation side-by-side: + +<md-tab-group> + + <md-tab label="src/app/heroes/heroes.component (v3)"> + {@example 'dependency-injection/ts/src/app/heroes/heroes.component.ts'} + </md-tab> + + + <md-tab label="src/app/heroes/heroes.component (v2)"> + {@example 'dependency-injection/ts/src/app/heroes/heroes.component.1.ts' region='full'} + </md-tab> + + +</md-tab-group> + + +## Dependency injection tokens + +When we register a provider with an injector, we associate that provider with a dependency injection token. +The injector maintains an internal *token-provider* map that it references when +asked for a dependency. The token is the key to the map. + +In all previous examples, the dependency value has been a class *instance*, and +the class *type* served as its own lookup key. +Here we get a `HeroService` directly from the injector by supplying the `HeroService` type as the token: + + +{@example 'dependency-injection/ts/src/app/injector.component.ts' region='get-hero-service'} + +We have similar good fortune when we write a constructor that requires an injected class-based dependency. +We define a constructor parameter with the `HeroService` class type, +and Angular knows to inject the +service associated with that `HeroService` class token: + + +{@example 'dependency-injection/ts/src/app/heroes/hero-list.component.ts' region='ctor-signature'} + +This is especially convenient when we consider that most dependency values are provided by classes. +### Non-class dependencies +<p> + What if the dependency value isn't a class? Sometimes the thing we want to inject is a +</p> + + +<p> + Applications often define configuration objects with lots of small facts + (like the title of the application or the address of a web API endpoint)  such as this one: +</p> + + + +{@example 'dependency-injection/ts/src/app/app.config.ts' region='config'} + +We'd like to make this configuration object available for injection. +We know we can register an object with a [value provider](#value-provider). +### OpaqueToken + +One solution to choosing a provider token for non-class dependencies is +to define and use an !{opaquetoken}. +The definition looks like this: + + +{@example 'dependency-injection/ts/src/app/app.config.ts' region='token'} + +We register the dependency provider using the `OpaqueToken` object: + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='providers-9'} + +Now we can inject the configuration object into any constructor that needs it, with +the help of an `@Inject` #{_decorator}: + + +{@example 'dependency-injection/ts/src/app/app.component.2.ts' region='ctor'} + + +Although the !{configType} interface plays no role in dependency injection, +it supports typing of the configuration object within the class. + +<div id='optional'> + +</div> + +## Optional dependencies + +Our `HeroService` *requires* a `Logger`, but what if it could get by without +a logger? +We can tell Angular that the dependency is optional by annotating the +constructor argument with `@Optional()`: + + +{@example 'dependency-injection/ts/src/app/providers.component.ts' region='provider-10-ctor'} + +When using `@Optional()`, our code must be prepared for a null value. If we +don't register a logger somewhere up the line, the injector will set the +value of `logger` to null. + +## Summary + +We learned the basics of Angular dependency injection in this chapter. +We can register various kinds of providers, +and we know how to ask for an injected object (such as a service) by +adding a parameter to a constructor. + +Angular dependency injection is more capable than we've described. +We can learn more about its advanced features, beginning with its support for +nested injectors, in the +[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) chapter. + +## Appendix: Working with injectors directly + +We rarely work directly with an injector, but +here's an `InjectorComponent` that does. + + +{@example 'dependency-injection/ts/src/app/injector.component.ts' region='injector'} + +An `Injector` is itself an injectable service. + +In this example, Angular injects the component's own `Injector` into the component's constructor. +The component then asks the injected injector for the services it wants. + +Note that the services themselves are not injected into the component. +They are retrieved by calling `injector.get`. + +The `get` method throws an error if it can't resolve the requested service. +We can call `get` with a second parameter (the value to return if the service is not found) +instead, which we do in one case +to retrieve a service (`ROUS`) that isn't registered with this or any ancestor injector. + +The technique we just described is an example of the +[service locator pattern](https://en.wikipedia.org/wiki/Service_locator_pattern). + +We **avoid** this technique unless we genuinely need it. +It encourages a careless grab-bag approach such as we see here. +It's difficult to explain, understand, and test. +We can't know by inspecting the constructor what this class requires or what it will do. +It could acquire services from any ancestor component, not just its own. +We're forced to spelunk the implementation to discover what it does. + +Framework developers may take this approach when they +must acquire services generically and dynamically. diff --git a/aio/content/guide/deployment.md b/aio/content/guide/deployment.md new file mode 100644 index 0000000000..eca02b80ae --- /dev/null +++ b/aio/content/guide/deployment.md @@ -0,0 +1,549 @@ +@title +Deployment + +@intro +Learn how to deploy your Angular app. + +@description +This page describes tools and techniques for deploy and optimize your Angular application. + + +{@a toc} +## Table of contents +* [Overview](#overview) +* [Simplest deployment possible](#dev-deploy) +* [Optimize for production](#optimize) + * [Ahead-of-Time (AOT) compilation](#aot) + * [Webpack](#webpack) + * [Tree shaking with _rollup_](#rollup) + * [Pruned libraries](#prune) + * [Measure performance first](#measure) +* [Angular configuration](#angular-configuration) + * [The `base` tag](#base-tag) + * [Enable production mode](#enable-prod-mode) + * [Lazy loading](#lazy-loading) +* [Server configuration](#server-configuration) + * [Routed apps must fallback to `index.html`](#fallback) + * [CORS: requesting services from a different server](#cors) + + +{@a overview} + +## Overview + +This guide describes techniques for preparing and deploying an Angular application to a server running remotely. +The techniques progress from _easy but suboptimal_ to _more optimal and more involved_. + +* The [simple way](#dev-deploy "Simplest deployment possible") is to copy the development environment to the server. + +* [_Ahead of Time_ compilation (AOT)](#aot "AOT Compilation") is the first of +[several optimization strategies](#optimize). +You'll also want to read the [detailed instructions in the AOT Cookbook](../cookbook/aot-compiler.html "AOT Cookbook"). + +* [Webpack](#webpack "Webpack Optimization") is a popular general purpose packaging tool with a rich ecosystem, including plugins for AOT. +The Angular [webpack guide](webpack.html "Webpack: an introduction") can get you started and +_this_ page provides additional optimization advice, but you'll probably have to learn more about webpack on your own. + +* The [Angular configuration](#angular-configuration "Angular configuration") section calls attention to +specific client application changes that could improve performance. + +* The [Server configuration](#server-configuration "Server configuration") section describes +server-side changes that may be necessary, _no matter how you deploy the application_. + + + +{@a dev-deploy} +## Simplest deployment possible + +The simplest way to deploy the app is to publish it to a web server +directly out of the development environment. + +It's already running locally. You'll just copy it, almost _as is_, +to a non-local server that others can reach. + +1. Copy _everything_ (or [_almost_ everything](#node-modules "Loading npm packages from the web")) +from the local project folder to a folder on the server. + +1. If you're serving the app out of a subfolder, +edit a version of `index.html` to set the `<base href>` appropriately. +For example, if the URL to `index.html` is `www.mysite.com/my/app/`, set the _base href_ to +`<base href="/my/app/">`. +Otherwise, leave it alone. +[More on this below](#base-tag). + +1. Configure the server to redirect requests for missing files to `index.html`. +[More on this below](#fallback). + +1. Enable production mode as [described below](#enable-prod-mode) (optional). + +That's the simplest deployment you can do. + + +~~~ {.alert.is-helpful} + +This is _not_ a production deployment. It's not optimized and it won't be fast for users. +It might be good enough for sharing your progress and ideas internally with managers, teammates, and other stakeholders. +Be sure to read about [optimizing for production](#optimize "Optimizing for production") below. + + + +~~~ + + + +{@a node-modules} +### Load npm package files from the web (SystemJS) + +The `node_modules` folder of _npm packages_ contains much more code +than is needed to actually run your app in the browser. +The `node_modules` for the Quickstart installation is typically 20,500+ files and 180+ MB. +The application itself requires a tiny fraction of that to run. + +It takes a long time to upload all of that useless bulk and +users will wait unnecessarily while library files download piecemeal. + +Load the few files you need from the web instead. + +(1) Make a copy of `index.html` for deployment and replace all `node_module` scripts +with versions that load from the web. It might look like this. + + +{@example 'deployment/ts/src/index.html' region='node-module-scripts'} + +(2) Replace the `systemjs.config.js` script with a script that +loads `systemjs.config.server.js`. + +{@example 'deployment/ts/src/index.html' region='systemjs-config'} + +(3) Add `systemjs.config.server.js` (shown in the code sample below) to the `src/` folder. +This alternative version configures _SystemJS_ to load _UMD_ versions of Angular +(and other third-party packages) from the web. + +Modify `systemjs.config.server.js` as necessary to stay in sync with changes +you make to `systemjs.config.js`. + +Notice the `paths` key: + + +{@example 'deployment/ts/src/systemjs.config.server.js' region='paths'} + +In the standard SystemJS config, the `npm` path points to the `node_modules/`. +In this server config, it points to +<a href="https://unpkg.com/" target="_blank" title="unpkg.com">https://unpkg.com</a>, +a site that hosts _npm packages_, +and loads them from the web directly. +There are other service providers that do the same thing. + +If you are unwilling or unable to load packages from the open web, +the inventory in `systemjs.config.server.js` identifies the files and folders that +you would copy to a library folder on the server. +Then change the config's `'npm'` path to point to that folder. + +### Practice with an example + +The following trivial router sample app shows these changes. + +<md-tab-group> + + <md-tab label="index.html"> + {@example 'deployment/ts/src/index.html'} + </md-tab> + + + <md-tab label="systemjs.config.server.js"> + {@example 'deployment/ts/src/systemjs.config.server.js'} + </md-tab> + + + <md-tab label="main.ts"> + {@example 'deployment/ts/src/main.ts'} + </md-tab> + + + <md-tab label="app/app.module.ts"> + {@example 'deployment/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="app/app.component.ts"> + {@example 'deployment/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="app/crisis-list.component.ts"> + {@example 'deployment/ts/src/app/crisis-list.component.ts'} + </md-tab> + + + <md-tab label="app/hero-list.component.ts"> + {@example 'deployment/ts/src/app/hero-list.component.ts'} + </md-tab> + + +</md-tab-group> + +Practice with this sample before attempting these techniques on your application. + +1. Follow the [setup instructions](../guide/setup.html "Angular QuickStart setup") for creating a new project +named <ngio-ex path="simple-deployment"></ngio-ex>. + +1. Add the "Simple deployment" sample files shown above. + +1. Run it with `npm start` as you would any project. + +1. Inspect the network traffic in the browser developer tools. +Notice that it loads all packages from the web. +You could delete the `node_modules` folder and the app would still run +(although you wouldn't be able to recompile or launch `lite-server` +until you restored it). + +1. Deploy the sample to the server (minus the `node_modules` folder!). + +When you have that working, try the same process on your application. + + +{@a optimize} + +## Optimize for production + +Although deploying directly from the development environment works, it's far from optimal. + +The client makes many small requests for individual application code and template files, +a fact you can quickly confirm by looking at the network tab in a browser's developer tools. +Each small file download can spend more time communicating with the server than tranfering data. + +Development files are full of comments and whitespace for easy reading and debugging. +The browser downloads entire libraries, instead of just the parts the app needs. +The volume of code passed from server to client (the "payload") +can be significantly larger than is strictly necessary to execute the application. + +The many requests and large payloads mean +the app takes longer to launch than it would if you optimized it. +Several seconds may pass (or worse) before the user can see or do anything userful. + +Does it matter? That depends upon business and technical factors you must evaluate for yourself. + +If it _does_ matter, there are tools and techniques to reduce the number of requests and the size of responses. + +- Ahead-of-Time (AOT) Compilation: pre-compiles Angular component templates. +- Bundling: concatenates modules into a single file (bundle). +- Inlining: pulls template html and css into the components. +- Minification: removes excess whitespace, comments, and optional tokens. +- Uglification: rewrites code to use short, cryptic variable and function names. +- Dead code elimination: removes unreferenced modules and unused code. +- Pruned libraries: drop unused libraries and pare others down to the features you need. +- Performance measurement: focus on optimizations that make a measurable difference. + +Each tool does something different. +They work best in combination and are mutually reinforcing. + +You can use any build system you like. +Whatever system you choose, be sure to automate it so that +building for production is a single step. + + +{@a aot} +### Ahead-of-Time (AOT) compilation + +The Angular _Ahead-of-Time_ compiler pre-compiles application components and their templates +during the build process. + +Apps compiled with AOT launch faster for several reasons. +* Application components execute immediately, without client-side compilation. +* Templates are embedded as code within their components so there is no client-side request for template files. +* You don't download the Angular compiler, which is pretty big on its own. +* The compiler discards unused Angular directives that a tree-shaking tool can then exclude. + +Learn more about AOT Compilation in the [AOT Cookbook](../cookbook/aot-compiler.html "AOT Cookbook") +which describes running the AOT compiler from the command line +and using [_rollup_](#rollup) for bundling, minification, uglification and tree shaking. + + +{@a webpack} +### Webpack (and AOT) + +<a href="https://webpack.js.org/" target="_blank" title="Webpack 2">Webpack 2</a> is another +great option for inlining templates and style-sheets, for bundling, minifying, and uglifying the application. +The "[Webpack: an introduction](webpack.html "Webpack: an introduction")" guide will get you started +using webpack with Angular. + +Consider configuring _Webpack_ with the official +<a href="https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack" target="_blank" title="Ahead-of-Time Webpack Plugin"> +Angular Ahead-of-Time Webpack Plugin</a>. +This plugin transpiles the TypeScript application code, +bundles lazy loaded `NgModules` separately, +and performs AOT compilation — without any changes to the source code. + + +{@a rollup} +### Dead code elimination with _rollup_ + +Any code that you don't call is _dead code_. +You can reduce the total size of the application substantially by removing dead code from the application and from third-party libraries. + +_Tree shaking_ is a _dead code elimination_ technique that removes entire exports from JavaScript modules. +If a library exports something that the application doesn't import, a tree shaking tool removes it from the code base. + +Tree shaking was popularized by +<a href="http://rollupjs.org/" target="_blank" title="Rollup">Rollup</a>, a popular tool with an ecosystem of +plugins for bundling, minification, and uglification. +Learn more about tree shaking and dead code elmination in +<a href="https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80#.15ih9cyvl" target="_blank" title="Tree-shaking and Dead Code Elimination"> +this post</a> by rollup-creator, Rich Harris. + + +{@a prune} +### Pruned libraries + +Don't count on automation to remove all dead code. + +Remove libraries that you don't use, especially unnecessary scripts in `index.html`. +Consider smaller alternatives to the libraries that you do use. + +Some libraries offer facilities for building a custom, skinny version with just the features you need. +Other libraries let you import features _a la carte_. +**RxJS** is a good example; import RxJS `Observable` operators individually instead of the entire library. + + +{@a measure} +### Measure performance first + +You can make better decisions about what to optimize and how when you have a clear and accurate understanding of +what's making the application slow. +The cause may not be what you think it is. +You can waste a lot of time and money optimizing something that has no tangible benefit or even makes the app slower. +You should measure the app's actual behavior when running in the environments that are important to you. + +The +<a href="https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing" target="_blank" title="Chrome DevTools Network Performance"> +Chrome DevTools Network Performance page</a> is a good place to start learning about measuring performance. + +The [WebPageTest](https://www.webpagetest.org/) tool is another good choice +that can also help verify that your deployment was successful. + + +{@a angular-configuration} + +## Angular configuration + +Angular configuration can make the difference between whether the app launches quickly or doesn't load at all. + + +{@a base-tag} +### The `base` tag + +The HTML [_<base href="..."/>_](https://angular.io/docs/ts/latest/guide/router.html#!#base-href) +specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. +For example, given the `<base href="/my/app/">`, the browser resolves a URL such as `some/place/foo.jpg` +into a server request for `my/app/some/place/foo.jpg`. +During navigation, the Angular router uses the _base href_ as the base path to component, template, and module files. + +See also the [*APP_BASE_HREF*](../api/common/index/APP_BASE_HREF-let.html "API: APP_BASE_HREF") alternative.In development, you typically start the server in the folder that holds `index.html`. +That's the root folder and you'd add `<base href="/">` near the top of `index.html` because `/` is the root of the app. + +But on the shared or production server, you might serve the app from a subfolder. +For example, when the URL to load the app is something like `http://www.mysite.com/mysrc/app/`, +the subfolder is `my/app/` and you should add `<base href="/my/app/">` to the server version of the `index.html`. + +When the `base` tag is misconfigured, the app fails to load and the browser console displays `404 - Not Found` errors +for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately. + + +{@a enable-prod-mode} +### Enable production mode + +Angular apps run in development mode by default, as you can see by the following message on the browser +console: + +<code-example format="nocode"> + Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode. +</code-example> + +Switching to production mode can make it run faster by disabling development specific checks such as the dual change detection cycles. + +To enable [production mode](../api/core/index/enableProdMode-function.html) when running remotely, add the following code to the `main.ts`. + + +{@example 'deployment/ts/src/main.ts' region='enableProdMode'} + + + +{@a lazy-loading} +### Lazy loading + +You can dramatically reduce launch time by only loading the application modules that +absolutely must be present when the app starts. + +Configure the Angular Router to defer loading of all other modules (and their associated code), either by +[waiting until the app has launched](router.html#preloading "Preloading") +or by [_lazy loading_](router.html#asynchronous-routing "Lazy loading") +them on demand. + +#### Don't eagerly import something from a lazy loaded module + +It's a common mistake. +You've arranged to lazy load a module. +But you unintentionally import it, with a JavaScript `import` statement, +in a file that's eagerly loaded when the app starts, a file such as the root `AppModule`. +If you do that, the module will be loaded immediately. + +The bundling configuration must take lazy loading into consideration. +Because lazy loaded modules aren't imported in JavaScript (as just noted), bundlers exclude them by default. +Bundlers don't know about the router configuration and won't create separate bundles for lazy loaded modules. +You have to create these bundles manually. + +The +[Angular Ahead-of-Time Webpack Plugin](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack) +automatically recognizes lazy loaded `NgModules` and creates separate bundles for them. + + + +{@a server-configuration} + +## Server configuration + +This section covers changes you may have make to the server or to files deployed to the server. + + +{@a fallback} +### Routed apps must fallback to `index.html` + +Angular apps are perfect candidates for serving with a simple static HTML server. +You don't need a server-side engine to dynamically compose application pages because +Angular does that on the client-side. + +If the app uses the Angular router, you must configure the server +to return the application's host page (`index.html`) when asked for a file that it does not have. + + +{@a deep-link} +A routed application should support "deep links". +A _deep link_ is a URL that specifies a path to a component inside the app. +For example, `http://www.mysite.com/heroes/42` is a _deep link_ to the hero detail page +that displays the hero with `id: 42`. + +There is no issue when the user navigates to that URL from within a running client. +The Angular router interprets the URL and routes to that page and hero. + +But clicking a link in an email, entering it in the browser address bar, +or merely refreshing the browser while on the hero detail page — +all of these actions are handled by the browser itself, _outside_ the running application. +The browser makes a direct request to the server for that URL, bypassing the router. + +A static server routinely returns `index.html` when it receives a request for `http://www.mysite.com/`. +But it rejects `http://www.mysite.com/heroes/42` and returns a `404 - Not Found` error *unless* it is +configured to return `index.html` instead. + +#### Fallback configuration examples + +There is no single configuration that works for every server. +The following sections describe configurations for some of the most popular servers. +The list is by no means exhaustive, but should provide you with a good starting point. + +#### Development servers + +- [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server installed with the +[Quickstart repo](https://github.com/angular/quickstart) is pre-configured to fallback to `index.html`. + +- [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): setup the +`historyApiFallback` entry in the dev server options as follows: + +<code-example> + historyApiFallback: { + disableDotRule: true, + htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] + } + +</code-example> + +#### Production servers + +- [Apache](https://httpd.apache.org/): add a +[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) +to the `.htaccess` file as show +[here](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/): +<code-example format="."> + RewriteEngine On + # If an existing asset or directory is requested go to it as it is + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d + RewriteRule ^ - [L] + + # If the requested resource doesn't exist, use index.html + RewriteRule ^ /index.html + +</code-example> + +- [NGinx](http://nginx.org/): use `try_files`, as described in +[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps), +modified to serve `index.html`: + +<code-example format="."> + try_files $uri $uri/ /index.html; + +</code-example> + +- [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown +[here](http://stackoverflow.com/a/26152011/2116927): +<code-example format="." escape="html"> + <system.webServer> + <rewrite> + <rules> + <rule name="Angular Routes" stopProcessing="true"> + <match url=".*" /> + <conditions logicalGrouping="MatchAll"> + <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> + <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> + </conditions> + <action type="Rewrite" url="/" /> + </rule> + </rules> + </rewrite> + </system.webServer> + +</code-example> + +- [GitHub Pages](https://pages.github.com/): you can't +[directly configure](https://github.com/isaacs/github/issues/408) +the GitHub Pages server, but you can add a 404 page. +Copy `index.html` into `404.html`. +It will still be served as the 404 response, but the browser will process that page and load the app properly. +It's also a good idea to +[serve from `docs/` on master](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch) +and to +[create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm) + +- [Firebase hosting](https://firebase.google.com/docs/hosting/): add a +[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites). + +<code-example format="."> + "rewrites": [ { + "source": "**", + "destination": "/index.html" + } ] + +</code-example> + + + +{@a cors} + +### Requesting services from a different server (CORS) + +Angular developers may encounter a +<a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" title="Cross-origin resource sharing"> +<i>cross-origin resource sharing</i></a> error when making a service request (typically a data service request). +to a server other than the application's own host server. +Browsers forbid such requests unless the server permits them explicitly. + +There isn't anything the client application can do about these errors. +The server must be configured to accept the application's requests. +Read about how to enable CORS for specific servers at +<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a>. + + +{@a next-steps} + +## Next steps + If you want to go beyond the [simple _copy-deploy_](#dev-deploy "Simplest deployment possible") approach, + read the [AOT Cookbook](../cookbook/aot-compiler.html "AOT Cookbook") next. \ No newline at end of file diff --git a/aio/content/guide/displaying-data.md b/aio/content/guide/displaying-data.md new file mode 100644 index 0000000000..32751392e3 --- /dev/null +++ b/aio/content/guide/displaying-data.md @@ -0,0 +1,186 @@ +@title +Displaying Data + +@intro +Property binding helps show app data in the UI. + +@description +You can display data by binding controls in an HTML template to properties of an Angular component. + +In this page, you'll create a component with a list of heroes. +You'll display the list of hero names and +conditionally show a message below the list. + +The final UI looks like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/displaying-data/final.png" alt="Final UI"> </img> +</figure> + +# Contents + +* [Showing component properties with interpolation](#interpolation). +* [Showing !{_an} !{_array} property with NgFor](#ngFor). +* [Conditional display with NgIf](#ngIf). + +The <live-example></live-example> demonstrates all of the syntax and code +snippets described in this page. + +## Showing component properties with interpolation +The easiest way to display a component property +is to bind the property name through interpolation. +With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`. + +Follow the [setup](setup.html) instructions for creating a new project +named <ngio-ex path="displaying-data"></ngio-ex>. + +Then modify the <ngio-ex path="app.component.ts"></ngio-ex> file by +changing the template and the body of the component. + +When you're done, it should look like this: + + +{@example 'displaying-data/ts/src/app/app.component.1.ts'} + +You added two properties to the formerly empty component: `title` and `myHero`. + +The revised template displays the two component properties using double curly brace +interpolation: +Angular automatically pulls the value of the `title` and `myHero` properties from the component and +inserts those values into the browser. Angular updates the display +when these properties change. + +More precisely, the redisplay occurs after some kind of asynchronous event related to +the view, such as a keystroke, a timer completion, or a response to an HTTP request. +Notice that you don't call **new** to create an instance of the `AppComponent` class. +Angular is creating an instance for you. How? + +The CSS `selector` in the `@Component` !{_decorator} specifies an element named `<my-app>`. +That element is a placeholder in the body of your `index.html` file: +When you bootstrap with the `AppComponent` class (in <ngio-ex path="main.ts"></ngio-ex>), Angular looks for a `<my-app>` +in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it +inside the `<my-app>` tag. + +Now run the app. It should display the title and hero name: +<figure class='image-display'> + <img src="/resources/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero"> </img> +</figure> + +## Template inline or template file? + +You can store your component's template in one of two places. +You can define it *inline* using the `template` property, or you can define +the template in a separate HTML file and link to it in +the component metadata using the `@Component` !{_decorator}'s `templateUrl` property. + +The choice between inline and separate HTML is a matter of taste, +circumstances, and organization policy. +Here the app uses inline HTML because the template is small and the demo +is simpler without the additional HTML file. + +In either style, the template data bindings have the same access to the component's properties. + +## Showing !{_an} !{_array} property with ***ngFor** + +To display a list of heroes, begin by adding !{_an} !{_array} of hero names to the component and redefine `myHero` to be the first name in the !{_array}. +Now use the Angular `ngFor` directive in the template to display +each item in the `heroes` list. +This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor` +in the `<li>` element is the Angular "repeater" directive. +It marks that `<li>` element (and its children) as the "repeater template": + + +~~~ {.alert.is-important} + +Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax. +For more information, see the [Template Syntax](./template-syntax.html#ngFor) page. + + +~~~ + +Notice the `hero` in the `ngFor` double-quoted instruction; +it is an example of a template input variable. Read +more about template input variables in the [microsyntax](./template-syntax.html#ngForMicrosyntax) section of +the [Template Syntax](./template-syntax.html) page. + +Angular duplicates the `<li>` for each item in the list, setting the `hero` variable +to the item (the hero) in the current iteration. Angular uses that variable as the +context for the interpolation in the double curly braces. + +In this case, `ngFor` is displaying !{_an} !{_array}, but `ngFor` can +repeat items for any [iterable](!{_iterableUrl}) object.Now the heroes appear in an unordered list. + +<figure class='image-display'> + <img src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor"> </img> +</figure> + + +## Creating a class for the data + +The app's code defines the data directly inside the component, which isn't best practice. +In a simple demo, however, it's fine. + +At the moment, the binding is to !{_an} !{_array} of strings. +In real applications, most bindings are to more specialized objects. + +To convert this binding to use specialized objects, turn the !{_array} +of hero names into !{_an} !{_array} of `Hero` objects. For that you'll need a `Hero` class. + +Create a new file in the `!{_appDir}` folder called <ngio-ex path="hero.ts"></ngio-ex> with the following code: + +## Using the Hero class + +After importing the `Hero` class, the `AppComponent.heroes` property can return a _typed_ !{_array} +of `Hero` objects: +Next, update the template. +At the moment it displays the hero's `id` and `name`. +Fix that to display only the hero's `name` property. +The display looks the same, but the code is clearer. + +## Conditional display with NgIf + +Sometimes an app needs to display a view or a portion of a view only under specific circumstances. + +Let's change the example to display a message if there are more than three heroes. + +The Angular `ngIf` directive inserts or removes an element based on a !{_boolean} condition. +To see it in action, add the following paragraph at the bottom of the template: + + +~~~ {.alert.is-important} + +Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax. +Read more about `ngIf` and `*` in the [ngIf section](./template-syntax.html#ngIf) of the [Template Syntax](./template-syntax.html) page. + + +~~~ + +The template expression inside the double quotes, +`*ngIf="heros.length > 3"`, looks and behaves much like !{_Lang}. +When the component's list of heroes has more than three items, Angular adds the paragraph +to the DOM and the message appears. If there are three or fewer items, Angular omits the +paragraph, so no message appears. For more information, +see the [template expressions](./template-syntax.html#template-expressions) section of the +[Template Syntax](./template-syntax.html) page. + + +~~~ {.alert.is-helpful} + +Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. That improves performance, especially in larger projects when conditionally including or excluding +big chunks of HTML with many data bindings. + + +~~~ + +Try it out. Because the !{_array} has four items, the message should appear. +Go back into <ngio-ex path="app.component.ts"></ngio-ex> and delete or comment out one of the elements from the hero !{_array}. +The browser should refresh automatically and the message should disappear. + +## Summary +Now you know how to use: +- **Interpolation** with double curly braces to display a component property. +- **ngFor** to display !{_an} !{_array} of items. +- A !{_Lang} class to shape the **model data** for your component and display properties of that model. +- **ngIf** to conditionally display a chunk of HTML based on a boolean expression. + +Here's the final code: diff --git a/aio/content/guide/forms.md b/aio/content/guide/forms.md new file mode 100644 index 0000000000..4a11e4b52c --- /dev/null +++ b/aio/content/guide/forms.md @@ -0,0 +1,736 @@ +@title +Forms + +@intro +A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors. + +@description +We’ve all used a form to log in, submit a help request, place an order, book a flight, +schedule a meeting, and perform countless other data entry tasks. +Forms are the mainstay of business applications. + +Any seasoned web developer can slap together an HTML form with all the right tags. +It's more challenging to create a cohesive data entry experience that guides the +user efficiently and effectively through the workflow behind the form. + +*That* takes design skills that are, to be frank, well out of scope for this guide. + +It also takes framework support for +**two-way data binding, change tracking, validation, and error handling** +... which we shall cover in this guide on Angular forms. + +We will build a simple form from scratch, one step at a time. Along the way we'll learn how to: + +- Build an Angular form with a component and template +- Use `ngModel` to create two-way data bindings for reading and writing input control values +- Track state changes and the validity of form controls +- Provide visual feedback using special CSS classes that track the state of the controls +- Display validation errors to users and enable/disable form controls +- Share information across HTML elements using template reference variables + +Run the <live-example></live-example>. + +## 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. + +That's not the only way to create a form but it's the way we'll cover in this guide.We can build almost any form we need with an Angular template — login forms, contact forms, pretty much any business form. +We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, +conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. + +It will be pretty easy because Angular handles many of the repetitive, boilerplate tasks we'd +otherwise wrestle with ourselves. + +We'll discuss and learn to build a template-driven form that looks like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form"> </img> +</figure> + +Here at the *Hero Employment Agency* we use this form to maintain personal information about heroes. +Every hero needs a job. It's our company mission to match the right hero with the right crisis! + +Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. + +If we delete the hero name, the form displays a validation error in an attention-grabbing style: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required"> </img> +</figure> + +Note that the submit button is disabled, and the "required" bar to the left of the input control changed from green to red. + +We'll customize the colors and location of the "required" bar with standard CSS. +We'll build this form in small steps: + +1. Create the `Hero` model class. +1. Create the component that controls the form. +1. Create a template with the initial form layout. +1. Bind data properties to each form control using the `ngModel` two-way data binding syntax. +1. Add a `name` attribute to each form input control. +1. Add custom CSS to provide visual feedback. +1. Show and hide validation error messages. +1. Handle form submission with **ngSubmit**. +1. Disable the form’s submit button until the form is valid. +## Setup + +Follow the [setup](setup.html) instructions for creating a new project +named <span ngio-ex>angular-forms</span>. + +## Create the Hero model class + +As users enter form data, we'll capture their changes and update an instance of a model. +We can't lay out the form until we know what the model looks like. + +A model can be as simple as a "property bag" that holds facts about a thing of application importance. +That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) +and one optional field (`alterEgo`). + +In the `!{_appDir}` directory, create the following file with the given content: + + +{@example 'forms/ts/src/app/hero.ts'} + +It's an anemic model with few requirements and no behavior. Perfect for our demo. + +The TypeScript compiler generates a public field for each `public` constructor parameter and +assigns the parameter’s value to that field automatically when we create new heroes. + +The `alterEgo` is optional, so the constructor lets us omit it; note the (?) in `alterEgo?`. + +We can create a new hero like this: + +## Create a form component + +An Angular form has two parts: an HTML-based _template_ and a component _class_ +to handle data and user interactions programmatically. +We begin with the class because it states, in brief, what the hero editor can do. + +Create the following file with the given content: +There’s nothing special about this component, nothing form-specific, +nothing to distinguish it from any component we've written before. + +Understanding this component requires only the Angular concepts covered in previous guides. + +1. The code imports the Angular core library, and the `Hero` model we just created. +1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `<hero-form>` tag. +1. The `moduleId: module.id` property sets the base for module-relative loading of the `templateUrl`. +1. The `templateUrl` property points to a separate file for the template HTML. +1. We defined dummy data for `model` and `powers`, as befits a demo. +Down the road, we can inject a data service to get and save real data +or perhaps expose these properties as +[inputs and outputs](./template-syntax.html#inputs-outputs) for binding to a +parent component. None of this concerns us now and these future changes won't affect our form. +1. We threw in a `diagnostic` property to return a JSON representation of our model. +It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. + +### Why the separate template file? + +Why don't we write the template inline in the component file as we often do elsewhere? + +There is no “right” answer for all occasions. We like inline templates when they are short. +Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to +write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code. +We also like short files with a clear and obvious purpose like this one. + +Form templates tend to be quite large even when displaying a small number of fields +so it's usually best to put the HTML template in a separate file. +We'll write that template file in a moment. Before we do, we'll take a step back +and revise the `app.module.ts` and `app.component.ts` to make use of the new `HeroFormComponent`. + +## Revise *app.module.ts* + +`app.module.ts` defines the application's root module. In it we identify the external modules we'll use in our application +and declare the components that belong to this module, such as our `HeroFormComponent`. + +Because template-driven forms are in their own module, we need to add the `FormsModule` to the array of +`imports` for our application module before we can use forms. + +Replace the contents of the "QuickStart" version with the following: + +{@example 'forms/ts/src/app/app.module.ts'} + + +There are three changes: + +1. We import `FormsModule` and our new `HeroFormComponent`. + +1. We add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives our application +access to all of the template-driven forms features, including `ngModel`. + +1. We add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes +the `HeroFormComponent` component visible throughout this module. + + +~~~ {.alert.is-important} + +If a component, directive, or pipe belongs to a module in the `imports` array, ​_DON'T_​ re-declare it in the `declarations` array. +If you wrote it and it should belong to this module, ​_DO_​ declare it in the `declarations` array. + + +~~~ + + +## Revise *app.component.ts* + +`AppComponent` is the application's root component. It will host our new `HeroFormComponent`. + +Replace the contents of the "QuickStart" version with the following: + + +{@example 'forms/ts/src/app/app.component.ts'} + + +There are only two changes. +The `template` is simply the new element tag identified by the component's `selector` property. +This will display the hero form when the application component is loaded. +We've also dropped the `name` field from the class body. + +## Create an initial HTML form template + +Create the new template file with the following contents: + + +{@example 'forms/ts/src/app/hero-form.component.html' region='start'} + +That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and +opening them up for user input in input boxes. + +The *Name* `<input>` control has the HTML5 `required` attribute; +the *Alter Ego* `<input>` control does not because `alterEgo` is optional. + +We've got a *Submit* button at the bottom with some classes on it for styling. + +**We are not using Angular yet**. There are no bindings, no extra directives, just layout. + +The `container`, `form-group`, `form-control`, and `btn` classes +come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic. +We're using Bootstrap to give the form a little style! + + +~~~ {.callout.is-important} + + +<header> + Angular forms do not require a style library +</header> + +Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or +the styles of any external library. Angular apps can use any CSS library, or none at all. + + +~~~ + +Let's add the stylesheet. Open `index.html` and add the following link to the `<head>`: + +## Add powers with _*ngFor_ + +Our hero must choose one super power from a fixed list of Agency-approved powers. +We maintain that list internally (in `HeroFormComponent`). + +We'll add a `select` to our +form and bind the options to the `powers` list using `ngFor`, +a technique seen previously in the [Displaying Data](./displaying-data.html) guide. + +Add the following HTML *immediately below* the *Alter Ego* group: +This code repeats the `<option>` tag for each power in the list of powers. +The `pow` template input variable is a different power in each iteration; +we display its name using the interpolation syntax. + +## Two-way data binding with _ngModel_ + +Running the app right now would be disappointing. + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/hero-form-3.png" width="400px" alt="Early form with no binding"> </img> +</figure> + +We don't see hero data because we are not binding to the `Hero` yet. +We know how to do that from earlier guides. +[Displaying Data](./displaying-data.html) taught us property binding. +[User Input](./user-input.html) showed us how to listen for DOM events with an +event binding and how to update a component property with the displayed value. + +Now we need to display, listen, and extract at the same time. + +We could use the techniques we already know, but +instead we'll introduce something new: the `[(ngModel)]` syntax, which +makes binding the form to the model super easy. + +Find the `<input>` tag for *Name* and update it like this: + +We added a diagnostic interpolation after the input tag +so we can see what we're doing. +We left ourselves a note to throw it away when we're done. +Focus on the binding syntax: `[(ngModel)]="..."`. + +If we run the app right now and started typing in the *Name* input box, +adding and deleting characters, we'd see them appearing and disappearing +from the interpolated text. +At some point it might look like this. + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/ng-model-in-action.png" width="400px" alt="ngModel in action"> </img> +</figure> + +The diagnostic is evidence that values really are flowing from the input box to the model and +back again. + +That's **two-way data binding**! +For more information about `[(ngModel)]` and two-way data bindings, see +the [Template Syntax](template-syntax.html#ngModel) page. +Notice that we also added a `name` attribute to our `<input>` tag and set it to "name" +which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful. +Defining a `name` attribute is a requirement when using `[(ngModel)]` in combination with a form. + +Internally Angular creates `FormControl` instances and +registers them with an `NgForm` directive that Angular attached to the `<form>` tag. +Each `FormControl` is registered under the name we assigned to the `name` attribute. +We'll talk about `NgForm` [later in this guide](#ngForm). +Let's add similar `[(ngModel)]` bindings and `name` attributes to *Alter Ego* and *Hero Power*. +We'll ditch the input box binding message +and add a new binding (at the top) to the component's `diagnostic` property. +Then we can confirm that two-way data binding works *for the entire hero model*. + +After revision, the core of our form should look like this: + +- Each input element has an `id` property that is used by the `label` element's `for` attribute +to match the label to its input control. +- Each input element has a `name` property that is required by Angular forms to register the control with the form. +If we run the app now and changed every hero model property, the form might display like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in action"> </img> +</figure> + +The diagnostic near the top of the form +confirms that all of our changes are reflected in the model. + +**Delete** the `{{diagnostic}}` binding at the top as it has served its purpose. + +## Track control state and validity with _ngModel_ + +A form isn't just about data binding. We'd also like to know the state of the controls in our form. + +Using `ngModel` in a form gives us more than just a two way data binding. It also tells +us if the user touched the control, if the value changed, or if the value became invalid. + +The *NgModel* directive doesn't just track state; it updates the control with special Angular CSS classes that reflect the state. +We can leverage those class names to change the appearance of the control. + +<table> + + <tr> + + <th> + State + </th> + + + <th> + Class if true + </th> + + + <th> + Class if false + </th> + + + </tr> + + + <tr> + + <td> + Control has been visited + </td> + + + <td> + <code>ng-touched</code> + </td> + + + <td> + <code>ng-untouched</code> + </td> + + + </tr> + + + <tr> + + <td> + Control's value has changed + </td> + + + <td> + <code>ng-dirty</code> + </td> + + + <td> + <code>ng-pristine</code> + </td> + + + </tr> + + + <tr> + + <td> + Control's value is valid + </td> + + + <td> + <code>ng-valid</code> + </td> + + + <td> + <code>ng-invalid</code> + </td> + + + </tr> + + +</table> + +Let's temporarily add a [template reference variable](./template-syntax.html#ref-vars) named `spy` +to the _Name_ `<input>` tag and use it to display the input's CSS classes. +Now run the app, and look at the _Name_ input box. +Follow the next four steps *precisely*: + +1. Look but don't touch. +1. Click inside the name box, then click outside it. +1. Add slashes to the end of the name. +1. Erase the name. + +The actions and effects are as follows: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/control-state-transitions-anim.gif" alt="Control State Transition"> </img> +</figure> + +We should see the following transitions and class names: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/ng-control-class-changes.png" width="500px" alt="Control state transitions"> </img> +</figure> + +The `ng-valid`/`ng-invalid` pair is the most interesting to us, because we want to send a +strong visual signal when the values are invalid. We also want to mark required fields. +To create such visual feedback, let's add definitions for the `ng-*` CSS classes. + +**Delete** the `#spy` template reference variable and the `TODO` as they have served their purpose. + +## Add custom CSS for visual feedback + +We can mark required fields and invalid data at the same time with a colored bar +on the left of the input box: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/validity-required-indicator.png" width="400px" alt="Invalid Form"> </img> +</figure> + +We achieve this effect by adding these class definitions to a new `forms.css` file +that we add to our project as a sibling to `index.html`: + + +{@example 'forms/ts/src/forms.css'} + +Update the `<head>` of `index.html` to include this style sheet: +## Show and hide validation error messages + +We can do better. The _Name_ input box is required and clearing it turns the bar red. +That says *something* is wrong but we don't know *what* is wrong or what to do about it. +We can leverage the control's state to reveal a helpful message. + +Here's the way it should look when the user deletes the name: + +<figure class='image-display'> + <img src="/resources/images/devguide/forms/name-required-error.png" width="400px" alt="Name required"> </img> +</figure> + +To achieve this effect we extend the `<input>` tag with +1. a [template reference variable](./template-syntax.html#ref-vars) +1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid. + +Here's an example of adding an error message to the _name_ input box: +We need a template reference variable to access the input box's Angular control from within the template. +Here we created a variable called `name` and gave it the value "ngModel". + +Why "ngModel"? +A directive's [exportAs](../api/core/index/Directive-decorator.html) property +tells Angular how to link the reference variable to the directive. +We set `name` to `ngModel` because the `ngModel` directive's `exportAs` property happens to be "ngModel". +We control visibility of the name error message by binding properties of the `name` +control to the message `<div>` element's `hidden` property. +In this example, we hide the message when the control is valid or pristine; +pristine means the user hasn't changed the value since it was displayed in this form. + +This user experience is the developer's choice. Some folks want to see the message at all times. +If we ignore the `pristine` state, we would hide the message only when the value is valid. +If we arrive in this component with a new (blank) hero or an invalid hero, +we'll see the error message immediately, before we've done anything. + +Some folks find that behavior disconcerting. +They only want to see the message when the user makes an invalid change. +Hiding the message while the control is "pristine" achieves that goal. +We'll see the significance of this choice when we [add a new hero](#new-hero) to the form. + +The hero *Alter Ego* is optional so we can leave that be. + +Hero *Power* selection is required. +We can add the same kind of error handling to the `<select>` if we want, +but it's not imperative because the selection box already constrains the +power to valid values. + +We'd like to add a new hero in this form. +We place a "New Hero" button at the bottom of the form and bind its click event to a `newHero` component method. + + +{@example 'forms/ts/src/app/hero-form.component.html' region='new-hero-button-no-reset'} + + + +{@example 'forms/ts/src/app/hero-form.component.ts' region='new-hero'} + +Run the application again, click the *New Hero* button, and the form clears. +The *required* bars to the left of the input box are red, indicating invalid `name` and `power` properties. +That's understandable as these are required fields. +The error messages are hidden because the form is pristine; we haven't changed anything yet. + +Enter a name and click *New Hero* again. +The app displays a **_Name is required_** error message! +We don't want error messages when we create a new (empty) hero. +Why are we getting one now? + +Inspecting the element in the browser tools reveals that the *name* input box is _no longer pristine_. +The form remembers that we entered a name before clicking *New Hero*. +Replacing the hero object *did not restore the pristine state* of the form controls. + +We have to clear all of the flags imperatively which we can do +by calling the form's `reset()` method after calling the `newHero()` method. + + +{@example 'forms/ts/src/app/hero-form.component.html' region='new-hero-button-form-reset'} + +Now clicking "New Hero" both resets the form and its control flags. + +## Submit the form with _ngSubmit_ + +The user should be able to submit this form after filling it in. +The Submit button at the bottom of the form +does nothing on its own, but it will +trigger a form submit because of its type (`type="submit"`). + +A "form submit" is useless at the moment. +To make it useful, bind the form's `ngSubmit` event property +to the hero form component's `onSubmit()` method: +We slipped in something extra there at the end! We defined a +template reference variable, **`#heroForm`**, and initialized it with the value "ngForm". + +The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole. + +### The _NgForm_ directive + +What `NgForm` directive? +We didn't add an [NgForm](../api/forms/index/NgForm-directive.html) directive! + +Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically. + +The `NgForm` directive supplements the `form` element with additional features. +It holds the controls we created for the elements with an `ngModel` directive +and `name` attribute, and monitors their properties including their validity. +It also has its own `valid` property which is true only *if every contained +control* is valid. +We'll bind the form's overall validity via +the `heroForm` variable to the button's `disabled` property +using an event binding. Here's the code: +If we run the application now, we find that the button is enabled +— although it doesn't do anything useful yet. + +Now if we delete the Name, we violate the "required" rule, which +is duly noted in the error message. +The Submit button is also disabled. + +Not impressed? Think about it for a moment. What would we have to do to +wire the button's enable/disabled state to the form's validity without Angular's help? + +For us, it was as simple as: + +1. Define a template reference variable on the (enhanced) form element. +2. Refer to that variable in a button many lines away. + +## Toggle two form regions (extra credit) + +Submitting the form isn't terribly dramatic at the moment. + +An unsurprising observation for a demo. To be honest, +jazzing it up won't teach us anything new about forms. +But this is an opportunity to exercise some of our newly won +binding skills. +If you aren't interested, go ahead and skip to this guide's conclusion. +Let's do something more strikingly visual. +Let's hide the data entry area and display something else. + +Start by wrapping the form in a `<div>` and bind +its `hidden` property to the `HeroFormComponent.submitted` property. +The main form is visible from the start because the +`submitted` property is false until we submit the form, +as this fragment from the `HeroFormComponent` shows: +When we click the Submit button, the `submitted` flag becomes true and the form disappears +as planned. + +Now the app needs to show something else while the form is in the submitted state. +Add the following HTML below the `<div>` wrapper we just wrote: +There's our hero again, displayed read-only with interpolation bindings. +This `<div>` appears only while the component is in the submitted state. + +The HTML includes an _Edit_ button whose click event is bound to an expression +that clears the `submitted` flag. + +When we click the _Edit_ button, this block disappears and the editable form reappears. + +That's as much drama as we can muster for now. + +## Conclusion + +The Angular form discussed in this guide takes advantage of the following +framework features to provide support for data modification, validation, and more: + +- An Angular HTML form template. +- A form component class with a `@Component` decorator. +- Handling form submission by binding to the `NgForm.ngSubmit` event property. +- Template reference variables such as `#heroForm` and `#name`. +- `[(ngModel)]` syntax for two-way data binding. +- The use of `name` attributes for validation and form element change tracking. +- The reference variable’s `valid` property on input controls to check if a control is valid and show/hide error messages. +- Controlling the submit button's enabled state by binding to `NgForm` validity. +- Custom CSS classes that provide visual feedback to users about invalid controls. + +Our final project folder structure should look like this: + +<aio-filetree> + + <aio-folder> + angular-forms + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + hero.ts + </aio-file> + + + <aio-file> + hero-form.component.html + </aio-file> + + + <aio-file> + hero-form.component.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +Here’s the code for the final version of the application: + +<md-tab-group> + + <md-tab label="hero-form.component.ts"> + {@example 'forms/ts/src/app/hero-form.component.ts' region='final'} + </md-tab> + + + <md-tab label="hero-form.component.html"> + {@example 'forms/ts/src/app/hero-form.component.html' region='final'} + </md-tab> + + + <md-tab label="hero.ts"> + {@example 'forms/ts/src/app/hero.ts'} + </md-tab> + + + <md-tab label="app.module.ts"> + {@example 'forms/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="app.component.ts"> + {@example 'forms/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="main.ts"> + {@example 'forms/ts/src/main.ts'} + </md-tab> + + + <md-tab label="index.html"> + {@example 'forms/ts/src/index.html'} + </md-tab> + + + <md-tab label="forms.css"> + {@example 'forms/ts/src/forms.css'} + </md-tab> + + +</md-tab-group> + diff --git a/aio/content/guide/glossary.md b/aio/content/guide/glossary.md new file mode 100644 index 0000000000..d21fcde906 --- /dev/null +++ b/aio/content/guide/glossary.md @@ -0,0 +1,6 @@ +@title +Glossary + +@intro +Brief definitions of the most important words in the Angular vocabulary + diff --git a/aio/content/guide/hierarchical-dependency-injection.md b/aio/content/guide/hierarchical-dependency-injection.md new file mode 100644 index 0000000000..96526737db --- /dev/null +++ b/aio/content/guide/hierarchical-dependency-injection.md @@ -0,0 +1,184 @@ +@title +Hierarchical Dependency Injectors + +@intro +Angular's hierarchical dependency injection system supports nested injectors in parallel with the component tree. + +@description +You learned the basics of Angular Dependency injection in the +[Dependency Injection](./dependency-injection.html) guide. + +Angular has a _Hierarchical Dependency Injection_ system. +There is actually a tree of injectors that parallel an application's component tree. +You can reconfigure the injectors at any level of that component tree. + +This guide explores this system and how to use it to your advantage. + +Try the <live-example></live-example>. + +## The injector tree + +In the [Dependency Injection](./dependency-injection.html) guide, +you learned how to configure a dependency injector and how to retrieve dependencies where you need them. + +In fact, there is no such thing as ***the*** injector. +An application may have multiple injectors. +An Angular application is a tree of components. Each component instance has its own injector. +The tree of components parallels the tree of injectors. + +The component's injector may be a _proxy_ for an ancestor injector higher in the component tree. +That's an implementation detail that improves efficiency. +You won't notice the difference and +your mental model should be that every component has its own injector. +Consider this guide's variation on the Tour of Heroes application. +At the top is the `AppComponent` which has some sub-components. +One of them is the `HeroesListComponent`. +The `HeroesListComponent` holds and manages multiple instances of the `HeroTaxReturnComponent`. +The following diagram represents the state of the this guide's three-level component tree when there are three instances of `HeroTaxReturnComponent` +open simultaneously. + +<figure class='image-display'> + <img src="/resources/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree" width="600"> </img> +</figure> + +### Injector bubbling + +When a component requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector. +If the component's injector lacks the provider, it passes the request up to its parent component's injector. +If that injector can't satisfy the request, it passes it along to *its* parent injector. +The requests keep bubbling up until Angular finds an injector that can handle the request or runs out of ancestor injectors. +If it runs out of ancestors, Angular throws an error. + +You can cap the bubbling. An intermediate component can declare that it is the "host" component. +The hunt for providers will climb no higher than the injector for that host component. +This a topic for another day. +### Re-providing a service at different levels +You can re-register a provider for a particular dependency token at multiple levels of the injector tree. +You don't *have* to re-register providers. You shouldn't do so unless you have a good reason. +But you *can*. + +As the resolution logic works upwards, the first provider encountered wins. +Thus, a provider in an intermediate injector intercepts a request for a service from something lower in the tree. +It effectively "reconfigures" and "shadows" a provider at a higher level in the tree. + +If you only specify providers at the top level (typically the root `AppModule`), the tree of injectors appears to be flat. +All requests bubble up to the root <span if-docs="ts"><code>NgModule</code></span> injector that you configured with the `!{_bootstrapModule}` method. + +## Component injectors + +The ability to configure one or more providers at different levels opens up interesting and useful possibilities. +### Scenario: service isolation + +Architectural reasons may lead you to restrict access to a service to the application domain where it belongs. + +The guide sample includes a `VillainsListComponent` that displays a list of villains. +It gets those villains from a `VillainsService`. + +While you could provide `VillainsService` in the root `AppModule` (that's where you'll find the `HeroesService`), +that would make the `VillainsService` available everywhere in the application, including the _Hero_ workflows. + +If you later modify the `VillainsService`, you could break something in a hero component somewhere. +That's not supposed to happen but the way you've provided the service creates that risk. + +Instead, provide the `VillainsService` in the `providers` metadata of the `VillainsListComponent` like this: + + +{@example 'hierarchical-dependency-injection/ts/src/app/villains-list.component.ts' region='metadata'} + +By providing `VillainsService` in the `VillainsListComponent` metadata — and nowhere else —, +the service becomes available only in the `VillainsListComponent` and its sub-component tree. +It's still a singleton, but it's a singleton that exist solely in the _villain_ domain. + +You are confident that a hero component can't access it. You've reduced your exposure to error. + +### Scenario: multiple edit sessions + +Many applications allow users to work on several open tasks at the same time. +For example, in a tax preparation application, the preparer could be working several tax returns, +switching from one to the other throughout the day. + +This guide demonstrates that scenario with an example in the Tour of Heroes theme. +Imagine an outer `HeroListComponent` that displays a list of super heroes. + +To open a hero's tax return, the preparer clicks on a hero name, which opens a component for editing that return. +Each selected hero tax return opens in its own component and multiple returns can be open at the same time. + +Each tax return component +* is its own tax return editing session. +* can change a tax return without affecting a return in another component. +* has the ability to save the changes to its tax return or cancel them. + +<figure class='image-display'> + <img src="/resources/images/devguide/dependency-injection/hid-heroes-anim.gif" width="400" alt="Heroes in action"> </img> +</figure> + +One might suppose that the `TaxReturnComponent` has logic to manage and restore changes. +That would be a pretty easy task for a simple hero tax return. +In the real world, with a rich tax return data model, the change management would be tricky. +You might delegate that management to a helper service, as this example does. + +Here is the `HeroTaxReturnService`. +It caches a single `HeroTaxReturn`, tracks changes to that return, and can save or restore it. +It also delegates to the application-wide, singleton `HeroService`, which it gets by injection. + +{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts'} + +Here is the `HeroTaxReturnComponent` that makes use of it. + +{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts'} + +The _tax-return-to-edit_ arrives via the input property which is implemented with getters and setters. +The setter initializes the component's own instance of the `HeroTaxReturnService` with the incoming return. +The getter always returns what that service says is the current state of the hero. +The component also asks the service to save and restore this tax return. + +There'd be big trouble if _this_ service were an application-wide singleton. +Every component would share the same service instance. +Each component would overwrite the tax return that belonged to another hero. +What a mess! + +Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `providers` property. + + +{@example 'hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts' region='providers'} + +The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`. +Recall that every component _instance_ has its own injector. +Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service. +No tax return overwriting. No mess. + +The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation. +You can review it and download it from the <live-example></live-example> +### Scenario: specialized providers + +Another reason to re-provide a service is to substitute a _more specialized_ implementation of that service, +deeper in the component tree. + +Consider again the Car example from the [Dependency Injection](./dependency-injection.html) guide. +Suppose you configured the root injector (marked as A) with _generic_ providers for +`CarService`, `EngineService` and `TiresService`. + +You create a car component (A) that displays a car constructed from these three generic services. + +Then you create a child component (B) that defines its own, _specialized_ providers for `CarService` and `EngineService` +that have special capabilites suitable for whatever is going on in component (B). + +Component (B) is the parent of another component (C) that defines its own, even _more specialized_ provider for `CarService`. + +<figure class='image-display'> + <img src="/resources/images/devguide/dependency-injection/car-components.png" alt="car components" width="220"> </img> +</figure> + +Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself. + +When you resolve an instance of `Car` at the deepest component (C), +its injector produces an instance of `Car` resolved by injector (C) with an `Engine` resolved by injector (B) and +`Tires` resolved by the root injector (A). + +<figure class='image-display'> + <img src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="car injector tree" width="600"> </img> +</figure> + + +The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample +which you can review and download from the <live-example></live-example> \ No newline at end of file diff --git a/aio/content/guide/index.md b/aio/content/guide/index.md new file mode 100644 index 0000000000..8eea27680c --- /dev/null +++ b/aio/content/guide/index.md @@ -0,0 +1,152 @@ +@title +Documentation Overview + +@intro +How to read and use this documentation + +@description +This page describes the Angular documentation at a high level. +If you're new to Angular, you may want to visit "[Learning Angular](learning-angular.html)" first. + +## Themes + +The documentation is divided into major thematic sections, each +a collection of pages devoted to that theme. + +<table width="100%"> + + <col width="15%"> + + </col> + + + <col> + + </col> + + + <tr style=top> + + <td> + <b><a href="../quickstart.html">QuickStart</a></b> + </td> + + + <td> + A first taste of Angular<span if-docs="ts"> with zero installation. + Run "Hello World" in an online code editor and start playing with live code</span>. + </td> + + + </tr> + + + <tr style=top> + + <td> + <b>Guide</b> + </td> + + + <td> + Learn the Angular basics (you're already here!) like the setup for local development, + displaying data and accepting user input, injecting application services into components, + and building simple forms. + </td> + + + </tr> + + + <tr style=top> + + <td> + <b><a href="../api/">API Reference</a></b> + </td> + + + <td> + Authoritative details about each of the Angular libraries. + </td> + + + </tr> + + + <tr style=top> + + <td> + <b><a href="../tutorial/">Tutorial</a></b> + </td> + + + <td> + A step-by-step, immersive approach to learning Angular that + introduces the major features of Angular in an application context. + </td> + + + </tr> + + + <tr style=top> + + <td> + <b><a href=" ">Advanced</a></b> + </td> + + + <td> + In-depth analysis of Angular features and development practices. + </td> + + + </tr> + + + <tr style=top if-docs="ts"> + + <td> + <b><a href="../cookbook/">Cookbook</a></b> + </td> + + + <td> + Recipes for specific application challenges, mostly code snippets with a minimum of exposition. + + </td> + + + </tr> + + +</table> + +A few early pages are written as tutorials and are clearly marked as such. +The rest of the pages highlight key points in code rather than explain each step necessary to build the sample. +You can always get the full source through the #{_liveLink}s. + +## Code samples + +Each page includes code snippets from a sample application that accompanies the page. +You can reuse these snippets in your applications. + +Look for a link to a running version of that sample, often near the top of the page, +such as this <live-example name="architecture"></live-example> from the [Architecture](architecture.html) page. +<span if-docs="ts"> +The link launches a browser-based, code editor where you can inspect, modify, save, and download the code. +</span> + +## Reference pages + +* The [Cheat Sheet](cheatsheet.html) lists Angular syntax for common scenarios. +* The [Glossary](glossary.html) defines terms that Angular developers should know. +<li if-docs="ts">The [Change Log](change-log.html) announces what's new and changed in the documentation.</li> +* The [API Reference](../api/) is the authority on every public-facing member of the Angular libraries. + +## Feedback + +We welcome feedback! + +* Use the <a href="!{_ngDocRepoURL}" target="_blank" title="angular docs on github">!{_angular_io} Github repository</a> for **documentation** issues and pull requests. +* Use the <a href="!{_ngRepoURL}" target="_blank" title="angular source on github">Angular Github repository</a> to report issues with **Angular** itself. \ No newline at end of file diff --git a/aio/content/guide/learning-angular.md b/aio/content/guide/learning-angular.md new file mode 100644 index 0000000000..9c402ce486 --- /dev/null +++ b/aio/content/guide/learning-angular.md @@ -0,0 +1,46 @@ +@title +Learning Angular + +@intro +A suggested path through the documentation for Angular newcomers + +@description + +<figure> + <img src="/resources/images/devguide/intro/people.png" width="200px" height="152px" alt="Us" align="left" style="margin-left:-40px;margin-right:10px"> </img> +</figure> + +Everyone learns differently. +You don't have to read the documentation straight through. Most pages stand on their own. +Those new to Angular may wish to follow this popular learning path. +<br class="l-clear-left"> + +1. [Setup](setup.html "Setup locally withe Quickstart seed") for local Angular development, if you haven't already done so. + +1. Take the [*Tour of Heroes* tutorial](../tutorial "Tour of Heroes"). + + The *Tour of Heroes* takes you step-by-step from [setup](setup.html) + to a full-featured example that demonstrates the essential characteristics of a professional application: + a sensible project structure, data binding, master/detail, services, dependency injection, navigation, and remote data access. + +1. <a id="architecture"></a>Read the [Architecture](architecture.html) overview for the big picture. + +1. [The Root Module](appmodule.html) introduces the `NgModule` class that tells Angular how to compile and run your application. + +1. [Displaying Data](displaying-data.html) shows how data binding puts component property values on screen. + +1. [User Input](user-input.html) explains how to respond to user-initiated DOM events. + +1. [Forms](forms.html) covers data entry and validation within the UI. + +1. [Dependency Injection](dependency-injection.html) is the way to build large, maintainable applications +from small, single-purpose parts. + +1. [Template Syntax](template-syntax.html) is a comprehensive study of Angular template HTML. + +After reading the above sections, feel free to skip around among the other pages on this site. + +### Next Step + +Try the [tutorial](../tutorial "Tour of Heroes") if you're ready to start coding or +visit the [Architecture](architecture.html "Basic Concepts") page if you prefer to learn the basic concepts first. \ No newline at end of file diff --git a/aio/content/guide/lifecycle-hooks.md b/aio/content/guide/lifecycle-hooks.md new file mode 100644 index 0000000000..6cf5311f44 --- /dev/null +++ b/aio/content/guide/lifecycle-hooks.md @@ -0,0 +1,679 @@ +@title +Lifecycle Hooks + +@intro +Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them. + +@description + +<figure> + <img src="/resources/images/devguide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px"> </img> +</figure> + +A component has a lifecycle managed by Angular itself. + +Angular creates it, renders it, creates and renders its children, +checks it when its data-bound properties change, and destroys it before removing it from the DOM. + +Angular offers **lifecycle hooks** +that provide visibility into these key life moments and the ability to act when they occur. + +A directive has the same set of lifecycle hooks, minus the hooks that are specific to component content and views. +<br class="l-clear-both">Try the <live-example></live-example>. + + +{@a hooks-overview} + +## Component lifecycle hooks +Directive and component instances have a lifecycle +as Angular creates, updates, and destroys them. +Developers can tap into key moments in that lifecycle by implementing +one or more of the *Lifecycle Hook* interfaces in the Angular `core` library. + +Each interface has a single hook method whose name is the interface name prefixed with `ng`. +For example, the `OnInit` interface has a hook method named `ngOnInit` +that Angular calls shortly after creating the component: + +{@example 'lifecycle-hooks/ts/src/app/peek-a-boo.component.ts' region='ngOnInit'} + +No directive or component will implement all of the lifecycle hooks and some of the hooks only make sense for components. +Angular only calls a directive/component hook method *if it is defined*. + + +{@a hooks-purpose-timing} + +## Lifecycle sequence +*After* creating a component/directive by calling its constructor, Angular +calls the lifecycle hook methods in the following sequence at specific moments: +<table width="100%"> + + <col width="20%"> + + </col> + + + <col width="80%"> + + </col> + + + <tr> + + <th> + Hook + </th> + + + <th> + Purpose and Timing + </th> + + + </tr> + + + <tr style=top> + + <td> + ngOnChanges + </td> + + + <td> + Respond when Angular (re)sets data-bound input properties. + The method receives a `SimpleChanges` object of current and previous property values. + + Called before `ngOnInit` and whenever one or more data-bound input properties change. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngOnInit + </td> + + + <td> + Initialize the directive/component after Angular first displays the data-bound properties + and sets the directive/component's input properties. + + Called _once_, after the _first_ `ngOnChanges`. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngDoCheck + </td> + + + <td> + Detect and act upon changes that Angular can't or won't detect on its own. + + Called during every change detection run, immediately after `ngOnChanges` and `ngOnInit`. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngAfterContentInit + </td> + + + <td> + Respond after Angular projects external content into the component's view. + + Called _once_ after the first `NgDoCheck`. + + _A component-only hook_. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngAfterContentChecked + </td> + + + <td> + Respond after Angular checks the content projected into the component. + + Called after the `ngAfterContentInit` and every subsequent `NgDoCheck`. + + _A component-only hook_. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngAfterViewInit + </td> + + + <td> + Respond after Angular initializes the component's views and child views. + + Called _once_ after the first `ngAfterContentChecked`. + + _A component-only hook_. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngAfterViewChecked + </td> + + + <td> + Respond after Angular checks the component's views and child views. + + Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked`. + + _A component-only hook_. + + </td> + + + </tr> + + + <tr style=top> + + <td> + ngOnDestroy + </td> + + + <td> + Cleanup just before Angular destroys the directive/component. + Unsubscribe observables and detach event handlers to avoid memory leaks. + + Called _just before_ Angular destroys the directive/component. + + </td> + + + </tr> + + +</table> + + + +{@a other-lifecycle-hooks} + +## Other lifecycle hooks + +Other Angular sub-systems may have their own lifecycle hooks apart from these component hooks. +3rd party libraries might implement their hooks as well in order to give developers more +control over how these libraries are used. + +## Lifecycle exercises + +The <live-example></live-example> +demonstrates the lifecycle hooks in action through a series of exercises +presented as components under the control of the root `AppComponent`. + +They follow a common pattern: a *parent* component serves as a test rig for +a *child* component that illustrates one or more of the lifecycle hook methods. + +Here's a brief description of each exercise: + +<table width="100%"> + + <col width="20%"> + + </col> + + + <col width="80%"> + + </col> + + + <tr> + + <th> + Component + </th> + + + <th> + Description + </th> + + + </tr> + + + <tr style=top> + + <td> + <a href="#peek-a-boo">Peek-a-boo</a> + </td> + + + <td> + Demonstrates every lifecycle hook. + Each hook method writes to the on-screen log. + </td> + + + </tr> + + + <tr style=top> + + <td> + <a href="#spy">Spy</a> + </td> + + + <td> + Directives have lifecycle hooks too. + A `SpyDirective` can log when the element it spies upon is + created or destroyed using the `ngOnInit` and `ngOnDestroy` hooks. + + This example applies the `SpyDirective` to a `<div>` in an `ngFor` *hero* repeater + managed by the parent `SpyComponent`. + </td> + + + </tr> + + + <tr style=top> + + <td> + <a href="#onchanges">OnChanges</a> + </td> + + + <td> + See how Angular calls the `ngOnChanges` hook with a `changes` object + every time one of the component input properties changes. + Shows how to interpret the `changes` object. + </td> + + + </tr> + + + <tr style=top> + + <td> + <a href="#docheck">DoCheck</a> + </td> + + + <td> + Implements an `ngDoCheck` method with custom change detection. + See how often Angular calls this hook and watch it post changes to a log. + </td> + + + </tr> + + + <tr style=top> + + <td> + <a href="#afterview">AfterView</a> + </td> + + + <td> + Shows what Angular means by a *view*. + Demonstrates the `ngAfterViewInit` and `ngAfterViewChecked` hooks. + </td> + + + </tr> + + + <tr style=top> + + <td> + <a href="#aftercontent">AfterContent</a> + </td> + + + <td> + Shows how to project external content into a component and + how to distinguish projected content from a component's view children. + Demonstrates the `ngAfterContentInit` and `ngAfterContentChecked` hooks. + </td> + + + </tr> + + + <tr style=top> + + <td> + Counter + </td> + + + <td> + Demonstrates a combination of a component and a directive + each with its own hooks. + + In this example, a `CounterComponent` logs a change (via `ngOnChanges`) + every time the parent component increments its input counter property. + Meanwhile, the `SpyDirective` from the previous example is applied + to the `CounterComponent` log where it watches log entries being created and destroyed. + + </td> + + + </tr> + + +</table> + +The remainder of this chapter discusses selected exercises in further detail. + + +{@a peek-a-boo} + +## Peek-a-boo: all hooks +The `PeekABooComponent` demonstrates all of the hooks in one component. + +You would rarely, if ever, implement all of the interfaces like this. +The peek-a-boo exists to show how Angular calls the hooks in the expected order. + +This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button. +<figure class='image-display'> + <img src="/resources/images/devguide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo"> </img> +</figure> + +The sequence of log messages follows the prescribed hook calling order: +`OnChanges`, `OnInit`, `DoCheck` (3x), `AfterContentInit`, `AfterContentChecked` (3x), +`AfterViewInit`, `AfterViewChecked` (3x), and `OnDestroy`. + +The constructor isn't an Angular hook *per se*. +The log confirms that input properties (the `name` property in this case) have no assigned values at construction.Had the user clicked the *Update Hero* button, the log would show another `OnChanges` and two more triplets of +`DoCheck`, `AfterContentChecked` and `AfterViewChecked`. +Clearly these three hooks fire a *often*. Keep the logic in these hooks as lean as possible! + +The next examples focus on hook details. + + +{@a spy} + +## Spying *OnInit* and *OnDestroy* + +Go undercover with these two spy hooks to discover when an element is initialized or destroyed. + +This is the perfect infiltration job for a directive. +The heroes will never know they're being watched. + +Kidding aside, pay attention to two key points: + +1. Angular calls hook methods for *directives* as well as components.<br><br> + +2. A spy directive can provide insight into a DOM object that you cannot change directly. +Obviously you can't touch the implementation of a native `div`. +You can't modify a third party component either. +But you can watch both with a directive. + +The sneaky spy directive is simple, consisting almost entirely of `ngOnInit` and `ngOnDestroy` hooks +that log messages to the parent via an injected `LoggerService`. + + +{@example 'lifecycle-hooks/ts/src/app/spy.directive.ts' region='spy-directive'} + +You can apply the spy to any native or component element and it'll be initialized and destroyed +at the same time as that element. +Here it is attached to the repeated hero `<div>` + +{@example 'lifecycle-hooks/ts/src/app/spy.component.html' region='template'} + +Each spy's birth and death marks the birth and death of the attached hero `<div>` +with an entry in the *Hook Log* as seen here: + +<figure class='image-display'> + <img src='/resources/images/devguide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive"> </img> +</figure> + +Adding a hero results in a new hero `<div>`. The spy's `ngOnInit` logs that event. + +The *Reset* button clears the `heroes` list. +Angular removes all hero `<div>` elements from the DOM and destroys their spy directives at the same time. +The spy's `ngOnDestroy` method reports its last moments. + +The `ngOnInit` and `ngOnDestroy` methods have more vital roles to play in real applications. + +### OnInit + +Use `ngOnInit` for two main reasons: +1. to perform complex initializations shortly after construction +1. to set up the component after Angular sets the input properties + +Experienced developers agree that components should be cheap and safe to construct. +Misko Hevery, Angular team lead, +[explains why](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/) +you should avoid complex constructor logic. +Don't fetch data in a component constructor. +You shouldn't worry that a new component will try to contact a remote server when +created under test or before you decide to display it. +Constructors should do no more than set the initial local variables to simple values. + +An `ngOnInit` is a good place for a component to fetch its initial data. The +[Tutorial](../tutorial/toh-pt4.html#oninit) and [HTTP](server-communication.html#oninit) chapter +show how. + + +Remember also that a directive's data-bound input properties are not set until _after construction_. +That's a problem if you need to initialize the directive based on those properties. +They'll have been set when `ngOninit` runs. +The `ngOnChanges` method is your first opportunity to access those properties. +Angular calls `ngOnChanges` before `ngOnInit` ... and many times after that. +It only calls `ngOnInit` once.You can count on Angular to call the `ngOnInit` method _soon_ after creating the component. +That's where the heavy initialization logic belongs. + +### OnDestroy + +Put cleanup logic in `ngOnDestroy`, the logic that *must* run before Angular destroys the directive. + +This is the time to notify another part of the application that the component is going away. + +This is the place to free resources that won't be garbage collected automatically. +Unsubscribe from observables and DOM events. Stop interval timers. +Unregister all callbacks that this directive registered with global or application services. +You risk memory leaks if you neglect to do so. + +## OnChanges + +Angular calls its `ngOnChanges` method whenever it detects changes to ***input properties*** of the component (or directive). +This example monitors the `OnChanges` hook. + +{@example 'lifecycle-hooks/ts/src/app/on-changes.component.ts' region='ng-on-changes'} + +The `ngOnChanges` method takes an object that maps each changed property name to a +[SimpleChange](../api/core/index/SimpleChange-class.html) object holding the current and previous property values. +This hook iterates over the changed properties and logs them. + +The example component, `OnChangesComponent`, has two input properties: `hero` and `power`. + +{@example 'lifecycle-hooks/ts/src/app/on-changes.component.ts' region='inputs'} + +The host `OnChangesParentComponent` binds to them like this: + + +{@example 'lifecycle-hooks/ts/src/app/on-changes-parent.component.html' region='on-changes'} + +Here's the sample in action as the user makes changes. + +<figure class='image-display'> + <img src='/resources/images/devguide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges"> </img> +</figure> + +The log entries appear as the string value of the *power* property changes. +But the `ngOnChanges` does not catch changes to `hero.name` +That's surprising at first. + +Angular only calls the hook when the value of the input property changes. +The value of the `hero` property is the *reference to the hero object*. +Angular doesn't care that the hero's own `name` property changed. +The hero object *reference* didn't change so, from Angular's perspective, there is no change to report! + +## DoCheck +Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch on its own. +Use this method to detect a change that Angular overlooked.The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck` hook: + +{@example 'lifecycle-hooks/ts/src/app/do-check.component.ts' region='ng-do-check'} + +This code inspects certain _values-of-interest_, capturing and comparing their current state against previous values. +It writes a special message to the log when there are no substantive changes to the `hero` or the `power` +so you can see how often `DoCheck` is called. The results are illuminating: + +<figure class='image-display'> + <img src='/resources/images/devguide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck"> </img> +</figure> + +While the `ngDoCheck` hook can detect when the hero's `name` has changed, it has a frightful cost. +This hook is called with enormous frequency — +after _every_ change detection cycle no matter where the change occurred. +It's called over twenty times in this example before the user can do anything. + +Most of these initial checks are triggered by Angular's first rendering of *unrelated data elsewhere on the page*. +Mere mousing into another input box triggers a call. +Relatively few calls reveal actual changes to pertinent data. +Clearly our implementation must be very lightweight or the user experience will suffer. + +## AfterView +The *AfterView* sample explores the `AfterViewInit` and `AfterViewChecked` hooks that Angular calls +*after* it creates a component's child views. + +Here's a child view that displays a hero's name in an input box: + +{@example 'lifecycle-hooks/ts/src/app/after-view.component.ts' region='child-view'} + +The `AfterViewComponent` displays this child view *within its template*: + +{@example 'lifecycle-hooks/ts/src/app/after-view.component.ts' region='template'} + +The following hooks take action based on changing values *within the child view* +which can only be reached by querying for the child view via the property decorated with +[@ViewChild](../api/core/index/ViewChild-decorator.html). + + +{@example 'lifecycle-hooks/ts/src/app/after-view.component.ts' region='hooks'} + + +<div id='wait-a-tick'> + +</div> + +### Abide by the unidirectional data flow rule +The `doSomething` method updates the screen when the hero name exceeds 10 characters. + + +{@example 'lifecycle-hooks/ts/src/app/after-view.component.ts' region='do-something'} + +Why does the `doSomething` method wait a tick before updating `comment`? + +Angular's unidirectional data flow rule forbids updates to the view *after* it has been composed. +Both of these hooks fire _after_ the component's view has been composed. + +Angular throws an error if the hook updates the component's data-bound `comment` property immediately (try it!).Here's *AfterView* in action +<figure class='image-display'> + <img src='/resources/images/devguide/lifecycle-hooks/after-view-anim.gif' alt="AfterView"> </img> +</figure> + +Notice that Angular frequently calls `AfterViewChecked`, often when there are no changes of interest. +Write lean hook methods to avoid performance problems. + +## AfterContent +The *AfterContent* sample explores the `AfterContentInit` and `AfterContentChecked` hooks that Angular calls +*after* Angular projects external content into the component. + +### Content projection +*Content projection* is a way to import HTML content from outside the component and insert that content +into the component's template in a designated spot. + +AngularJS developers know this technique as *transclusion*. +Consider this variation on the [previous _AfterView_](#afterview) example. +This time, instead of including the child view within the template, it imports the content from +the `AfterContentComponent`'s parent. Here's the parent's template. + +{@example 'lifecycle-hooks/ts/src/app/after-content.component.ts' region='parent-template'} + +Notice that the `<my-child>` tag is tucked between the `<after-content>` tags. +Never put content between a component's element tags *unless you intend to project that content +into the component*. + +Now look at the component's template: + +{@example 'lifecycle-hooks/ts/src/app/after-content.component.ts' region='template'} + +The `<ng-content>` tag is a *placeholder* for the external content. +It tells Angular where to insert that content. +In this case, the projected content is the `<my-child>` from the parent. +<figure class='image-display'> + <img src='/resources/images/devguide/lifecycle-hooks/projected-child-view.png' width="230" alt="Projected Content"> </img> +</figure> + + +The tell-tale signs of *content projection* are (a) HTML between component element tags +and (b) the presence of `<ng-content>` tags in the component's template.### AfterContent hooks +*AfterContent* hooks are similar to the *AfterView* hooks. +The key difference is in the child component + +* The *AfterView* hooks concern `ViewChildren`, the child components whose element tags +appear *within* the component's template. + +* The *AfterContent* hooks concern `ContentChildren`, the child components that Angular +projected into the component. + +The following *AfterContent* hooks take action based on changing values in a *content child* +which can only be reached by querying for it via the property decorated with +[@ContentChild](../api/core/index/ContentChild-decorator.html). + + +{@example 'lifecycle-hooks/ts/src/app/after-content.component.ts' region='hooks'} + + + +{@a no-unidirectional-flow-worries} +### No unidirectional flow worries with _AfterContent..._ + +This component's `doSomething` method update's the component's data-bound `comment` property immediately. +There's no [need to wait](#wait-a-tick). + +Recall that Angular calls both *AfterContent* hooks before calling either of the *AfterView* hooks. +Angular completes composition of the projected content *before* finishing the composition of this component's view. +There is a small window between the `AfterContent...` and `AfterView...` hooks to modify the host view. \ No newline at end of file diff --git a/aio/content/guide/ngcontainer.md b/aio/content/guide/ngcontainer.md new file mode 100644 index 0000000000..da6effa122 --- /dev/null +++ b/aio/content/guide/ngcontainer.md @@ -0,0 +1,12 @@ +@description + +<style> + h4 {font-size: 17px !important; text-transform: none !important;} + .syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; } + +</style> + +This guide has been withdrawn. +The essential information about this feature +is in the [Structural Directives](structural-directives.html#ngcontainer) guide. +The original draft has been retained for possible future use. \ No newline at end of file diff --git a/aio/content/guide/ngmodule.md b/aio/content/guide/ngmodule.md new file mode 100644 index 0000000000..9bca9656ee --- /dev/null +++ b/aio/content/guide/ngmodule.md @@ -0,0 +1,1216 @@ +@title +Angular Modules (NgModule) + +@intro +Define application modules with @NgModule + +@description +**Angular Modules** help organize an application into cohesive blocks of functionality. + +An Angular Module 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, +making some of them public so external components can use them. +It 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. + +This page goes into Angular modules in much 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 ...") +* [Feature modules](#feature-modules "Partition the app into feature modules") +* [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: + +* <live-example plnkr="minimal.0">A minimal NgModule app</live-example> +* <live-example plnkr="contact.1b">The first contact module</live-example> +* <live-example plnkr="contact.2">The revised contact module</live-example> +* <live-example plnkr="pre-shared.3">Just before adding _SharedModule_</live-example> +* <live-example>The final version</live-example> + +### Frequently Asked Questions (FAQs) + +This page covers Angular Module concepts in a tutorial fashion. + +The companion [Angular Module FAQs](../cookbook/ngmodule-faq.html "Angular Module FAQs") cookbook +offers ready answers to specific design and implementation questions. +Read this page first before hopping over to those FAQs. + +<div class='l-hr'> + +</div> + + + +{@a angular-modularity} + +## Angular Modularity + +Modules are a great way to organize the 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., +<a href="https://material.angular.io/" target="_blank">Material Design</a>, +<a href="http://ionicframework.com/" target="_blank">Ionic</a>, +<a href="https://github.com/angular/angularfire2" target="_blank">AngularFire2</a>). + +Angular modules 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. + +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: + +* 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. + +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** +that represent collections of related functionality. +We then import these modules into the _root module_. + +We'll see how later in the page. Let's start with the _root module_. + + +{@a 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`. + +The `AppModule` from the [_QuickStart seed_](setup.html) is about as minimal as it gets: + +{@example 'setup/ts/src/app/app.module.ts'} + +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 metadata imports a single helper module, `BrowserModule`, the module 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. + +The `declarations` list identifies the application's only component, +the _root component_, the top of this app's rather bare component tree. + +The example `AppComponent` simply displays a data-bound title: + +{@example 'ngmodule/ts/src/app/app.component.0.ts'} + +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 `<my-app>` element tags of the `index.html` + + +{@a bootstrap} + +## Bootstrapping in _main.ts_ +We 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. + +### 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. + + +{@example 'ngmodule/ts/src/main.ts'} + +The samples in this page demonstrate the dynamic bootstrapping approach. + +<live-example embedded plnkr="minimal.0" img="devguide/ngmodule/minimal-plunker.png">Try the live example.</live-example> + + +### 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, +producing a collection of class factories in their own files. +Among them is the `AppModuleNgFactory`. + +The syntax for bootstrapping the pre-compiled `AppModuleNgFactory` is similar to +the dynamic version that bootstraps the `AppModule` class. + + +{@example 'ngmodule/ts/src/main-static.ts'} + +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. + +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. + +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`. + +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`. + +<div class='l-hr'> + +</div> + + + +{@a declarations} + +## Declare directives and components +The app evolves. +The first addition is a `HighlightDirective`, an [attribute directive](attribute-directives.html) +that sets the background color of the attached element. + +{@example 'ngmodule/ts/src/app/highlight.directive.ts'} + +We update the `AppComponent` template to attach the directive to the title: + +{@example 'ngmodule/ts/src/app/app.component.1.ts' region='template'} + +If we ran the app now, Angular would not recognize the `highlight` attribute and would ignore it. +We must declare the directive in `AppModule`. + +Import the `HighlightDirective` class and add it to the module's `declarations` like this: + +{@example 'ngmodule/ts/src/app/app.module.1.ts' region='directive'} + +### Add a component + +We decide to refactor the title into its own `TitleComponent`. +The component's template binds to the component's `title` and `subtitle` properties like this: + +{@example 'ngmodule/ts/src/app/title.component.html' region='v1'} + + + +{@example 'ngmodule/ts/src/app/title.component.ts' region='v1'} + +We rewrite the `AppComponent` to display the new `TitleComponent` in the `<app-title>` element, +using an input binding to set the `subtitle`. + +{@example 'ngmodule/ts/src/app/app.component.1.ts'} + +Angular won't recognize the `<app-title>` tag until we declare it in `AppModule`. +Import the `TitleComponent` class and add it to the module's `declarations`: + +{@example 'ngmodule/ts/src/app/app.module.1.ts' region='component'} + + + +{@a 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 +with [providers](dependency-injection.html#providers) at different levels of the +application's component tree. + +A module can add providers to the application's root dependency injector, making those services +available everywhere in the application. + +Many applications capture information about the currently logged-in user and make that information +accessible through a user service. +This sample application has a dummy implementation of such a `UserService`. + + +{@example 'ngmodule/ts/src/app/user.service.ts'} + +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. + +{@example 'ngmodule/ts/src/app/title.component.html'} + +Update the `TitleComponent` class with a constructor that injects the `UserService` +and sets the component's `user` property from the service. + +{@example 'ngmodule/ts/src/app/title.component.ts'} + +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: + +{@example 'ngmodule/ts/src/app/app.module.1.ts' region='providers'} + + + +{@a imports} + +## 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. +There is no message if there is no user. + +{@example 'ngmodule/ts/src/app/title.component.html' region='ngIf'} + +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. +The initial version of `AppModule` imports `BrowserModule`. + +{@example 'ngmodule/ts/src/app/app.module.0.ts' region='imports'} + +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. +More accurately, `NgIf` is declared in `CommonModule` from `@angular/common`. + +`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. +The net effect is that an importer of `BrowserModule` gets `CommonModule` directives automatically.Many familiar Angular directives do not 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. + +To illustrate this point, we 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. + +The `ContactComponent` presents a "contact editor", +implemented with _Angular Forms_ in the [_template-driven form_](forms.html) style. + +### 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. + +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 `ContactComponent` selector matches an element named `<app-contact>`. +Add an element with that name to the `AppComponent` template just below the `<app-title>`: + +{@example 'ngmodule/ts/src/app/app.component.1b.ts' region='template'} + +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`, +and an alternative version of the `HighlightDirective`. + +To make it manageable, we place all contact-related material in an `src/app/contact` folder +and break the component into three constituent HTML, TypeScript, and css files: +<md-tab-group> + + <md-tab label="src/app/contact/contact.component.html"> + {@example 'ngmodule/ts/src/app/contact/contact.component.html'} + </md-tab> + + + <md-tab label="src/app/contact/contact.component.ts"> + {@example 'ngmodule/ts/src/app/contact/contact.component.3.ts'} + </md-tab> + + + <md-tab label="src/app/contact/contact.component.css"> + {@example 'ngmodule/ts/src/app/contact/contact.component.css'} + </md-tab> + + + <md-tab label="src/app/contact/contact.service.ts"> + {@example 'ngmodule/ts/src/app/contact/contact.service.ts'} + </md-tab> + + + <md-tab label="src/app/contact/awesome.pipe.ts"> + {@example 'ngmodule/ts/src/app/contact/awesome.pipe.ts'} + </md-tab> + + + <md-tab label="src/app/contact/highlight.directive.ts"> + {@example 'ngmodule/ts/src/app/contact/highlight.directive.ts'} + </md-tab> + + +</md-tab-group> + +Focus on the component template. +Notice the two-way data binding `[(ngModel)]` in the middle of the template. +`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`. + +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. + +### Import the FormsModule + +Add the `FormsModule` to the `AppModule` metadata's `imports` list. + +{@example 'ngmodule/ts/src/app/app.module.1.ts' region='imports'} + +Now `[(ngModel)]` binding will work and the user input will be validated by Angular Forms, +once we declare our new component, pipe and directive. + + +~~~ {.alert.is-critical} + +**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_. + +**Never re-declare classes that belong to another module.** + + +~~~ + + + +{@a declare-pipe} +### Declare the contact component, directive and pipe + +The application fails to compile until we declare the contact component, directive and pipe. +Update the `declarations` in the `AppModule` accordingly: + +{@example 'ngmodule/ts/src/app/app.module.1.ts' region='declarations'} + + + +{@a import-name-conflict} + +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: + +{@example 'ngmodule/ts/src/app/app.module.1b.ts' region='import-alias'} + +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). +### Provide 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. + +In this app we chose to add `ContactService` to the `AppModule` metadata's `providers` list: + +{@example 'ngmodule/ts/src/app/app.module.1b.ts' region='providers'} + +Now `ContactService` (like `UserService`) can be injected into any component in the application. + + +{@a 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**. + + Architecturally, the `ContactService` belongs to the Contact business domain. + 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 + so they can't have their own provider scopes. + + This omission is intentional. + Angular modules 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. + To inject `ContactService`, you must first import its _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. +### Run the app +Everything is now in place to run the application with its contact editor. + +The app file structure looks like this: +<aio-filetree> + + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + highlight.directive.ts + </aio-file> + + + <aio-file> + title.component.(html|ts) + </aio-file> + + + <aio-file> + user.service.ts + </aio-file> + + + <aio-folder> + contact + <aio-file> + awesome.pipe.ts + </aio-file> + + + <aio-file> + contact.component.(css|html|ts) + </aio-file> + + + <aio-file> + contact.service.ts + </aio-file> + + + <aio-file> + highlight.directive.ts + </aio-file> + + + </aio-folder> + + + </aio-folder> + + +</aio-filetree> + +Try the example: +<live-example embedded plnkr="contact.1b" img="devguide/ngmodule/contact-1b-plunker.png"></live-example> + + +{@a resolve-conflicts} + +## 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. + +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. +<md-tab-group> + + <md-tab label="src/app/highlight.directive.ts"> + {@example 'ngmodule/ts/src/app/highlight.directive.ts'} + </md-tab> + + + <md-tab label="src/app/contact/highlight.directive.ts"> + {@example 'ngmodule/ts/src/app/contact/highlight.directive.ts'} + </md-tab> + + +</md-tab-group> + +Will Angular use only one of them? No. +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 +when it should stay gold. + +The real problem is that there are _two different classes_ trying to do the same thing. + +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 +they take turns modifying the same HTML element. +At least the app still compiles. +If we 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 +that insulate the declarations in one module from the declarations in another. + + +{@a 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`. + +* 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_. + +### _Feature Module_ + +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 +are available to all. + +There are two 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. + +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. + +While we can do everything within the root module, +feature modules help us 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. + +In the next section, we carve the contact functionality out of the root module +and into a dedicated feature module. + +<a id="contact-module-v1"></a> +### Make _Contact_ a feature module + +It's easy to refactor the contact material into a contact feature module. + +1. Create the `ContactModule` in the `src/app/contact` folder. +1. Move the contact material from `AppModule` to `ContactModule`. +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. + +### Add the _ContactModule_ + +Here's the new `ContactModule` + +{@example 'ngmodule/ts/src/app/contact/contact.module.2.ts'} + +We copy from `AppModule` the contact-related import statements and the `@NgModule` properties +that concern the contact and paste them in `ContactModule`. + +We _import_ the `FormsModule` because the contact component needs it. + +~~~ {.alert.is-important} + +Modules do not 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`. + +~~~ + +We also replaced `BrowserModule` by `CommonModule` for reasons explained in +[an FAQ](../cookbook/ngmodule-faq.html#q-browser-vs-common-module). + +We _declare_ the contact component, directive, and pipe in the module `declarations`. + +We _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. +The `AwesomePipe` and `HighlightDirective` are hidden from the rest of the application. +The `HighlightDirective` can no longer color the `AppComponent` title text. +### 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). +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. +<md-tab-group> + + <md-tab label="src/app/app.module.ts (v2)"> + {@example 'ngmodule/ts/src/app/app.module.2.ts'} + </md-tab> + + + <md-tab label="src/app/app.module.ts (v1)"> + {@example 'ngmodule/ts/src/app/app.module.1b.ts'} + </md-tab> + + +</md-tab-group> + +### ImprovementsThere'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's simpler: + * Fewer import statements + * No `FormsModule` import + * No contact-specific declarations + * No `ContactService` provider + * No `HighlightDirective` conflict + +Try this `ContactModule` version of the sample. + +<live-example embedded plnkr="contact.2" img="devguide/ngmodule/contact-2-plunker.png">Try the live example.</live-example> + + +{@a lazy-load} + +## 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. +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. +Examine and download the complete source for this version from the +<live-example plnkr="pre-shared.3" img="devguide/ngmodule/v3-plunker.png">live example.</live-example>Some facets of the current application merit discussion. + +* The app has three feature modules: Contact, Hero, and Crisis. +* The Angular router helps users navigate among these modules. +* The `ContactComponent` is the default destination when the app starts. +* The `ContactModule` continues to be "eagerly" loaded when the application starts. +* `HeroModule` and the `CrisisModule` are lazy loaded. + +<a id="app-component-template"></a> +Let's start at the top with the new `AppComponent` template: +a title, three links, and a `<router-outlet>`. + +{@example 'ngmodule/ts/src/app/app.component.3.ts' region='template'} + +The `<app-contact>` element is gone; we're routing to the _Contact_ page now. + +The `AppModule` has changed modestly: + +{@example 'ngmodule/ts/src/app/app.module.3.ts'} + + +Some file names bear a `.3` extension indicating +a difference with prior or future versions. +We'll explain differences that matter in due course. +The module still imports `ContactModule` so that its routes and components are mounted when the app starts. + +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) +that handles the app's routing concerns. + +### App routing + +{@example 'ngmodule/ts/src/app/app-routing.module.ts'} + +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. + +This 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 `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. + +The remaining two routes use lazy loading syntax to tell the router where to find the modules: + +{@example 'ngmodule/ts/src/app/app-routing.module.ts' region='lazy-routes'} + + +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 `#`. +### RouterModule.forRoot + +The `forRoot` static class method of the `RouterModule` with the provided configuration, +added to the `imports` array provides the routing concerns for the module. + +{@example 'ngmodule/ts/src/app/app-routing.module.ts' region='forRoot'} + +The returned `AppRoutingModule` class is a `Routing Module` containing both the `RouterModule` directives +and the Dependency Injection providers that produce a configured `Router`. + +This `AppRoutingModule` is intended for the app _root_ module _only_. + + +~~~ {.alert.is-critical} + +Never call `RouterModule.forRoot` in a feature routing module. + +~~~ + +Back in the root `AppModule`, we add the `AppRoutingModule` to its `imports` list, +and the app is ready to navigate. + +{@example 'ngmodule/ts/src/app/app.module.3.ts' region='imports'} + +### 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: + +{@example 'ngmodule/ts/src/app/contact/contact-routing.module.ts' region='routing'} + +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. + + +~~~ {.alert.is-important} + +Always call `RouterModule.forChild` in a feature routing module. + + +~~~ + + + +~~~ {.alert.is-helpful} + +**_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. + + +~~~ + +`ContactModule` has changed in two small but important details +<md-tab-group> + + <md-tab label="src/app/contact/contact.module.3.ts"> + {@example 'ngmodule/ts/src/app/contact/contact.module.3.ts' region='class'} + </md-tab> + + + <md-tab label="src/app/contact/contact.module.2.ts"> + {@example 'ngmodule/ts/src/app/contact/contact.module.2.ts' region='class'} + </md-tab> + + +</md-tab-group> + +1. It imports the `ContactRoutingModule` object from `contact-routing.module.ts` +1. 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. +No template will ever again reference this `ContactComponent`. +It's gone from the [_AppComponent_ template](#app-component-template). + + +{@a hero-module} +### Lazy loaded routing to a 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: + +<aio-filetree> + + <aio-folder> + hero + <aio-file> + hero-detail.component.ts + </aio-file> + + + <aio-file> + hero-list.component.ts + </aio-file> + + + <aio-file> + hero.component.ts + </aio-file> + + + <aio-file> + hero.module.ts + </aio-file> + + + <aio-file> + hero-routing.module.ts + </aio-file> + + + <aio-file> + hero.service.ts + </aio-file> + + + <aio-file> + highlight.directive.ts + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +This is the child routing scenario familiar to readers of the [Router](router.html#child-routing-component) page. +The `HeroComponent` is the feature's top component and routing host. +Its template has a `<router-outlet>` 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. + +The `HeroModule` is a feature module like any other. + +{@example 'ngmodule/ts/src/app/hero/hero.module.3.ts' region='class'} + +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. + +<live-example embedded plnkr="pre-shared.3" img="devguide/ngmodule/v3-plunker.png">Try the live example.</live-example> + + +{@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. + +Let's 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` + +Most of this is familiar blocking and tackling. Here is the `SharedModule` + +{@example 'ngmodule/ts/src/app/shared/shared.module.ts'} + +Some highlights +* 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 +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`. + +We 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`. + +`SharedModule` can still export `FormsModule` without listing it among its `imports`. + +### 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. + +The `TitleComponent` is used _only once_ by the `AppComponent`. +There's no point in sharing it. + +<a id="no-shared-module-providers"></a> +### Why _UserService_ isn't shared + +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. + +`UserService` is an application-wide singleton. +We 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} + +Do **not** specify app-wide singleton `providers` in a shared module. +A lazy loaded module that imports that shared module will make its own copy of the service. + + +~~~ + + + +{@a core-module} + +## 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. + +Instead, we'll gather them in a single `CoreModule` that we **import _once_ when the app starts** +and _never import anywhere else_. + +**Steps:** + +* 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` + +{@example 'ngmodule/ts/src/app/core/core.module.ts' region='v4'} + + +We're importing some extra symbols from the Angular core library that we're not using yet. +They'll become relevant later in this page.The `@NgModule` metadata should be familiar. +We declare the `TitleComponent` because this module _owns_ it and we 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`. + +`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. + +### Why bother? +This scenario is clearly contrived. +The app is too small to worry about a single service file and a tiny, one-time component. + +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. + +Real world apps have more to worry about. +They can have several single-use components (e.g., 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. +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. + +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. + +We recommend collecting such single-use classes and hiding their gory details inside a `CoreModule`. +A simplified root `AppModule` imports `CoreModule` in its capacity as orchestrator of the application as a whole. + +## Cleanup +Having refactored to a `CoreModule` and a `SharedModule`, it's time to cleanup the other modules. + +### A trimmer _AppModule_ + +Here is the updated `AppModule` paired with version 3 for comparison: +<md-tab-group> + + <md-tab label="src/app/app.module.ts (v4)"> + {@example 'ngmodule/ts/src/app/app.module.ts' region='v4'} + </md-tab> + + + <md-tab label="src/app/app.module.ts (v3)"> + {@example 'ngmodule/ts/src/app/app.module.3.ts'} + </md-tab> + + +</md-tab-group> + +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. + +### A trimmer _ContactModule_ +Here is the new `ContactModule` paired with the prior version: +<md-tab-group> + + <md-tab label="src/app/contact/contact.module.ts (v4)"> + {@example 'ngmodule/ts/src/app/contact/contact.module.ts'} + </md-tab> + + + <md-tab label="src/app/contact/contact.module.ts (v3)"> + {@example 'ngmodule/ts/src/app/contact/contact.module.3.ts'} + </md-tab> + + +</md-tab-group> + +Notice that +* The `AwesomePipe` and `HighlightDirective` are gone. +* The imports include `SharedModule` instead of `CommonModule` and `FormsModule` +* This new version is leaner and cleaner. + +<div class='l-hr'> + +</div> + + + +{@a core-for-root} + +## Configure core services with _CoreModule.forRoot_ + +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. +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 + +The root `AppModule` imports the `CoreModule` and adds the `providers` to the `AppModule` providers. +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 +over the providers of imported modules.Let's add a `CoreModule.forRoot` method that configures the core `UserService`. + +We've extended the core `UserService` with an optional, injected `UserServiceConfig`. +If a `UserServiceConfig` exists, the `UserService` sets the user name from that config. + +{@example 'ngmodule/ts/src/app/core/user.service.ts' region='ctor'} + +Here's `CoreModule.forRoot` that takes a `UserServiceConfig` object: + +{@example 'ngmodule/ts/src/app/core/core.module.ts' region='for-root'} + +Lastly, we call it _within the_ `imports` _list_ of the `AppModule`. + +{@example 'ngmodule/ts/src/app/app.module.ts' region='import-for-root'} + +The app displays "Miss Marple" as the user instead of the default "Sherlock Holmes". + + +~~~ {.alert.is-important} + +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. + +Remember to _import_ the result; don't add it to any other `@NgModule` list. + + +~~~ + + +<div class='l-hr'> + +</div> + + + +{@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. + +We could _hope_ that no developer makes that mistake. +Or we can guard against it and fail fast by adding the following `CoreModule` constructor. + +{@example 'ngmodule/ts/src/app/core/core.module.ts' region='ctor'} + +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._" + +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. +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). + +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.### Conclusion + +You made it! You can examine and download the complete source for this final version from the live example. +<live-example embedded img="devguide/ngmodule/final-plunker.png"></live-example> + +### 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 +with its ready answers to specific design and implementation questions. \ No newline at end of file diff --git a/aio/content/guide/npm-packages.md b/aio/content/guide/npm-packages.md new file mode 100644 index 0000000000..804f842326 --- /dev/null +++ b/aio/content/guide/npm-packages.md @@ -0,0 +1,206 @@ +@title +Npm Packages + +@intro +Recommended npm packages, and how to specify package dependencies + +@description +Angular applications and Angular itself depend upon features and functionality provided by a variety of third-party packages. +These packages are maintained and installed with the Node Package Manager (<a href="https://docs.npmjs.com/" target="_blank">npm</a>). +Node.js and npm are essential to Angular development. + +<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm"> +Get them now</a> if they're not already installed on your machine. + +**Verify that you are running node `v4.x.x` or higher and npm `3.x.x` or higher** +by running the commands `node -v` and `npm -v` in a terminal/console window. +Older versions produce errors. + +We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm. You may need [nvm](https://github.com/creationix/nvm) if you already have projects running on your machine that use other versions of node and npm. +We recommend a comprehensive starter-set of packages as specified in the `dependencies` and `devDependencies` +sections of the <a href="https://docs.npmjs.com/files/package.json" target="_blank">package.json</a> file +installed as described during [Setup](setup.html).You can use other packages but we recommend *this particular set* to start with because (a) they work well together and +(b) they include everything you'll need to build and run the sample applications in this series. +Note: A cookbook or guide page may require an additional library such as *jQuery*.You'll install more than you need for QuickStart. +No worries! +You only serve to the client those packages that the application actually requests. + +This page explains what each package does. You can make substitutions later to suit your tastes and experience. + +## *dependencies* and *devDependencies* +The `package.json` includes two sets of packages, +[dependencies](#dependencies) and [devDependencies](#dev-dependencies). + +The *dependencies* are essential to *running* the application. +The *devDependencies* are only necessary to *develop* the application. +You can exclude them from production installations by adding `--production` to the install command, as follows: +<code-example format="." language="bash"> + npm install my-application --production + +</code-example> + + + +{@a dependencies} + +## *dependencies* +The `dependencies` section of `package.json` contains: + +* ***Features*** - Feature packages give the application framework and utility capabilities. + +* ***Polyfills*** - Polyfills plug gaps in the browser's JavaScript implementation. + +* ***Other*** - Other libraries that support the application such as `bootstrap` for HTML widgets and styling. + +### Feature Packages + +***@angular/core*** - Critical runtime parts of the framework needed by every application. +Includes all metadata decorators, `Component`, `Directive`, dependency injection, and the component lifecycle hooks. + +***@angular/common*** - The commonly needed services, pipes, and directives provided by the Angular team. + +***@angular/compiler*** - Angular's *Template Compiler*. +It understands templates and can convert them to code that makes the application run and render. +Typically you don’t interact with the compiler directly; rather, you use it indirectly via `platform-browser-dynamic` or the offline template compiler. + +***@angular/platform-browser*** - Everything DOM and browser related, especially the pieces that help render into DOM. +This package also includes the bootstrapStatic method for bootstrapping applications for production builds that pre-compile templates offline. + +***@angular/platform-browser-dynamic*** - Includes [Providers](../api/core/index/Provider-type-alias.html) and a [bootstrap](ngmodule.html#bootstrap) method for applications that +compile templates on the client. Don’t use offline compilation. +Use this package for bootstrapping during development and for bootstrapping plunker samples. + +***@angular/http*** - Angular's http client. + +***@angular/router*** - Component router. + +***@angular/upgrade*** - Set of utilities for upgrading AngularJS applications to Angular. + +***[system.js](https://github.com/systemjs/systemjs)*** - A dynamic module loader compatible with the +[ES2015 module](http://www.2ality.com/2014/09/es6-modules-final.html) specification. +Other viable choices include the well-regarded [webpack](https://webpack.github.io/). + +Your future applications are likely to require additional packages that provide +HTML controls, themes, data access, and various utilities. + + + +{@a polyfills} + +### Polyfill packages + +Angular requires certain [polyfills](https://en.wikipedia.org/wiki/Polyfill) in the application environment. +Install these polyfills using the npm packages that Angular lists in the *peerDependencies* section of its `package.json`. + +You must list these packages in the `dependencies` section of your own `package.json`. + +For background on this requirement, see [Why peerDependencies?](#why-peer-dependencies).***core-js*** - Patches the global context (window) with essential features of ES2015 (ES6). + You may substitute an alternative polyfill that provides the same core APIs. + When these APIs are implemented by the major browsers, this dependency will become unnecessary. + +***rxjs*** - A polyfill for the [Observables specification](https://github.com/zenparsing/es-observable) currently before the +[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language. +You can pick a preferred version of *rxjs* (within a compatible version range) +without waiting for Angular updates. + +***zone.js*** - A polyfill for the [Zone specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the +[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language. +You can pick a preferred version of *zone.js* to use (within a compatible version range) +without waiting for Angular updates. + + +{@a other} + +### Other helper libraries + +***angular-in-memory-web-api*** - An Angular-supported library that simulates a remote server's web api +without requiring an actual server or real http calls. +Good for demos, samples, and early stage development (before we even have a server). +Read about it in the [Http Client](server-communication.html#appendix-tour-of-heroes-in-memory-server) page. + +***bootstrap*** - [Bootstrap](http://getbootstrap.com/) is a popular HTML and CSS framework for designing responsive web apps. +Some of the samples improve their appearance with *bootstrap*. + + +{@a dev-dependencies} + +## *devDependencies* +The packages listed in the *devDependencies* section of the `package.json` help you develop the application. +You don't have to deploy them with the production application although there is no harm in doing so. + +***[concurrently](https://www.npmjs.com/package/concurrently)*** - +A utility to run multiple *npm* commands concurrently on OS/X, Windows, and Linux operating systems. + +***[lite-server](https://www.npmjs.com/package/lite-server)*** - +A light-weight, static file server, by [John Papa](http://johnpapa.net/) +with excellent support for Angular apps that use routing. + +***[typescript](https://www.npmjs.com/package/typescript)*** - +the TypeScript language server, including the *tsc* TypeScript compiler. + +***@types/\**** - TypeScript definition files. +Learn more about it in the [TypeScript Configuration](typescript-configuration.html#typings) chapter. + + + +{@a why-peer-dependencies} +## Why *peerDependencies*? + +There isn't a *peerDependencies* section in the QuickStart `package.json`. +But Angular has a *peerDependencies* section in +*its* package.json, which has important consequences for your application. + +It explains why you load the [polyfill](#polyfills) *dependency* packages in the QuickStart `package.json`, +and why you'll need those packages in your own applications. + +An explanation of [peer dependencies](https://nodejs.org/en/blog/npm/peer-dependencies/) follows. + +Packages depend on other packages. For example, your application depends on the Angular package. + +Two packages, "A" and "B", could depend on the same third package "C". +"A" and "B" might both list "C" among their *dependencies*. + +What if "A" and "B" depend on different versions of "C" ("C1" and "C2"). The npm package system supports that. +It installs "C1" in the `node_modules` folder for "A" and "C2" in the `node_modules` folder for "B". +Now "A" and "B" have their own copies of "C" and they run without interferring with one another. + +But there is a problem. Package "A" may require the presence of "C1" without actually calling upon it directly. +"A" may only work if *everyone is using "C1"*. It falls down if any part of the application relies on "C2". + +The solution is for "A" to declare that "C1" is a *peer dependency*. + +The difference between a `dependency` and a `peerDependency` is roughly this: + +>A **dependency** says, "I need this thing directly available to *me*." +> +>A **peerDependency** says, "If you want to use me, you need this thing available to *you*." + +The Angular `package.json` specifies several *peer dependency* packages, +each pinned to a particular version of a third-party package. + +### We must install Angular's *peerDependencies* ourselves. + +When *npm* installs packages listed in *your* `dependencies` section, +it also installs the packages listed within *their* packages `dependencies` sections. +The process is recursive. + +However, as of version 3, *npm* does *not* install packages listed in *peerDependencies* sections. + +This means that when your application installs Angular, ***npm* doesn't automatically install +the packages listed in Angular's *peerDependencies* section**. + +Fortunately, *npm* issues a warning (a) When any *peer dependencies* are missing, or (b) +When the application or any of its other dependencies +installs a different version of a *peer dependency*. + +These warnings guard against accidental failures due to version mismatches. +They leave you in control of package and version resolution. + +It is your responsibility to list all *peer dependency* packages **among your own *devDependencies***. + +#### The future of *peerDependencies* + +The Angular polyfill dependencies are hard requirements. Currently, there is no way to make them optional. + +However, there is an npm feature request for "optional peerDependencies," which would allow you to model this relationship better. +When this feature request is implemented, Angular will switch from *peerDependencies* to *optionalPeerDependencies* for all polyfills. \ No newline at end of file diff --git a/aio/content/guide/reactive-forms.md b/aio/content/guide/reactive-forms.md new file mode 100644 index 0000000000..423d4e9041 --- /dev/null +++ b/aio/content/guide/reactive-forms.md @@ -0,0 +1,1159 @@ +@title +Reactive Forms + +@intro +Create a reactive form using FormBuilder, groups, and arrays. + +@description +_Reactive forms_ is an Angular technique for creating forms in a _reactive_ style. +This guide explains reactive forms as you follow the steps to build a "Hero Detail Editor" form. + + +{@a toc} +## Contents + +- [Introduction to reactive forms](#intro) +- [Setup](#setup) +- [Create a data model](#data-model) +- [Create a _reactive forms_ component](#create-component) +- [Create its template file](#create-template) +- [Import the _ReactiveFormsModule_](#import) +- [Display the _HeroDetailComponent_](#update) +- [Add a FormGroup](#formgroup) +- [Taking a look at the form model](#json) +- [Introduction to _FormBuilder_](#formbuilder) +- [Validators.required](#validators) +- [Nested FormGroups](#grouping) +- [Inspect _FormControl_ properties](#properties) +- [Set form model data using _setValue_ and _patchValue_](#set-data) +- [Use _FormArray_ to present an array of _FormGroups_](#form-array) +- [Observe control changes](#observe-control) +- [Save form data](#save) + +Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker">Reactive Forms live-example</live-example>. + +You can also run the <live-example title="Reactive Forms Demo in Plunker">Reactive Forms Demo</live-example> version +and choose one of the intermediate steps from the "demo picker" at the top. + + +{@a intro} +## Introduction to Reactive Forms + +Angular offers two form-building technologies: _reactive_ forms and _template-driven_ forms. +The two technologies belong to the `@angular/forms` library +and share a common set of form control classes. + +But they diverge markedly in philosophy, programming style, and technique. +They even have their own modules: the `ReactiveFormsModule` and the `FormsModule`. + +### _Reactive_ forms +Angular _reactive_ forms facilitate a _reactive style_ of programming +that favors explicit management of the data flowing between +a non-UI _data model_ (typically retrieved from a server) and a +UI-oriented _form model_ that retains the states +and values of the HTML controls on screen. Reactive forms offer the ease +of using reactive patterns, testing, and validation. + +With _reactive_ forms, you create a tree of Angular form control objects +in the component class and bind them to native form control elements in the +component template, using techniques described in this guide. + +You create and manipulate form control objects directly in the +component class. As the component class has immediate access to both the data +model and the form control structure, you can push data model values into +the form controls and pull user-changed values back out. The component can +observe changes in form control state and react to those changes. + +One advantage of working with form control objects directly is that value and validity updates +are [always synchronous and under your control](#async-vs-sync "Async vs sync"). +You won't encounter the timing issues that sometimes plague a template-driven form +and reactive forms can be easier to unit test. + +In keeping with the reactive paradigm, the component +preserves the immutability of the _data model_, +treating it as a pure source of original values. +Rather than update the data model directly, +the component extracts user changes and forwards them to an external component or service, +which does something with them (such as saving them) +and returns a new _data model_ to the component that reflects the updated model state. + +Using reactive form directives does not require you to follow all reactive priniciples, +but it does facilitate the reactive programming approach should you choose to use it. + +### _Template-driven_ forms + +_Template-driven_ forms, introduced in the [Template guide](forms.html), take a completely different approach. + +You place HTML form controls (such as `<input>` and `<select>`) in the component template and +bind them to _data model_ properties in the component, using directives +like `ngModel`. + +You don't create Angular form control objects. Angular directives +create them for you, using the information in your data bindings. +You don't push and pull data values. Angular handles that for you with `ngModel`. +Angular updates the mutable _data model_ with user changes as they happen. + +For this reason, the `ngModel` directive is not part of the ReactiveFormsModule. + +While this means less code in the component class, +[template-driven forms are asynchronous](#async-vs-sync "Async vs sync") +which may complicate development in more advanced scenarios. + + +{@a async-vs-sync} +### Async vs. sync + +Reactive forms are synchronous. Template-driven forms are asynchronous. It's a difference that matters. + +In reactive forms, you create the entire form control tree in code. +You can immediately update a value or drill down through the descendents of the parent form +because all controls are always available. + +Template-driven forms delegate creation of their form controls to directives. +To avoid "_changed after checked_" errors, +these directives take more than one cycle to build the entire control tree. +That means you must wait a tick before manipulating any of the controls +from within the component class. + +For example, if you inject the form control with a `@ViewChild(NgForm)` query and examine it in the +[`ngAfterViewInit` lifecycle hook](lifecycle-hooks.html#afterview "Lifecycle hooks guide: AfterView"), +you'll discover that it has no children. +You must wait a tick, using `setTimeout`, before you can +extract a value from a control, test its validity, or set it to a new value. + +The asynchrony of template-driven forms also complicates unit testing. +You must wrap your test block in `async()` or `fakeAsync()` to +avoid looking for values in the form that aren't there yet. +With reactive forms, everything is available when you expect it to be. + +### Which is better, reactive or template-driven? + +Neither is "better". +They're two different architectural paradigms, +with their own strengths and weaknesses. +Choose the approach that works best for you. +You may decide to use both in the same application. + +The balance of this _reactive forms_ guide explores the _reactive_ paradigm and +concentrates exclusively on reactive forms techniques. +For information on _template-driven forms_, see the [_Forms_](forms.html) guide. + +In the next section, you'll set up your project for the reactive form demo. +Then you'll learn about the [Angular form classes](#essentials) and how to use them in a reactive form. + + + +{@a setup} +## Setup + +Follow the steps in the [_Setup_ guide](../setup.html "Setup guide") +for creating a new project folder (perhaps called `reactive-forms`) +based on the _QuickStart seed_. + + + +{@a data-model} +## Create a data model +The focus of this guide is a reactive forms component that edits a hero. +You'll need a `hero` class and some hero data. +Create a new `data-model.ts` file in the `app` directory and copy the content below into it. + + +{@example 'reactive-forms/ts/src/app/data-model.ts'} + +The file exports two classes and two constants. The `Address` +and `Hero` classes define the application _data model_. +The `heroes` and `states` constants supply the test data. + + + +{@a create-component} +## Create a _reactive forms_ component +Make a new file called +`hero-detail.component.ts` in the `app` directory and import these symbols: + + +{@example 'reactive-forms/ts/src/app/hero-detail-1.component.ts' region='imports'} + +Now enter the `@Component` decorator that specifies the `HeroDetailComponent` metadata: + + +{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='metadata'} + +The `moduleId: module.id` lets you use +[component-relative paths](./cookbook/component-relative-paths.html) in file URLs +such as when specifying the `templateUrl`. + +Next, create an exported `HeroDetailComponent` class with a `FormControl`. +`FormControl` is a directive that allows you to create and manage +a `FormControl` instance directly. + + + +{@example 'reactive-forms/ts/src/app/hero-detail-1.component.ts' region='v1'} + +Here you are creating a `FormControl` called `name`. +It will be bound in the template to an HTML `input` box for the hero name. + +A `FormControl` constructor accepts three, optional arguments: +the initial data value, an array of validators, and an array of async validators. + +This simple control doesn't have data or validators. +In real apps, most form controls have both. + +This guide touches only briefly on `Validators`. For an in-depth look at them, +read the [Form Validation](../cookbook/form-validation.html) cookbook. + + + +{@a create-template} +## Create the template + +Now create the component's template, `src/app/hero-detail.component.html`, with the following markup. + + +{@example 'reactive-forms/ts/src/app/hero-detail-1.component.html' region='simple-control'} + +To let Angular know that this is the input that you want to +associate to the `name` `FormControl` in the class, +you need `[formControl]="name"` in the template on the `<input>`. + + +Disregard the `form-control` _CSS_ class. It belongs to the +<a href="http://getbootstrap.com/" target="_blank" title="Bootstrap CSS">Bootstrap CSS library</a>, +not Angular. +It _styles_ the form but in no way impacts the logic of the form. + + +{@a import} +## Import the _ReactiveFormsModule_ + +The HeroDetailComponent template uses `formControlName` +directive from the `ReactiveFormsModule`. + +In this sample, you declare the `HeroDetailComponent` in the `AppModule`. +Therefore, do the following three things in `app.module.ts`: +1. Use a JavaScript `import` statement to access +the `ReactiveFormsModule` and the `HeroDetailComponent`. +1. Add `ReactiveFormsModule` to the `AppModule`'s `imports` list. +1. Add `HeroDetailComponent` to the declarations array. + + +{@example 'reactive-forms/ts/src/app/app.module.ts' region='v1'} + + + +{@a update} + +## Display the _HeroDetailComponent_ +Revise the `AppComponent` template so it displays the `HeroDetailComponent`. + +{@example 'reactive-forms/ts/src/app/app.component.1.ts'} + + + +{@a essentials} +### Essential form classes +It may be helpful to read a brief description of the core form classes. + +* [_AbstractControl_](../api/forms/index/AbstractControl-class.html "API Reference: AbstractControl") +is the abstract base class for the three concrete form control classes: +`FormControl`, `FormGroup`, and `FormArray`. +It provides their common behaviors and properties, some of which are _observable_. + +* [_FormControl_](../api/forms/index/FormControl-class.html "API Reference: FormControl") +tracks the value and validity status of an _individual_ form control. +It corresponds to an HTML form control such as an input box or selector. + +* [_FormGroup_](../api/forms/index/FormGroup-class.html "API Reference: FormGroup") +tracks the value and validity state of a _group_ of `AbstractControl` instances. +The group's properties include its child controls. +The top-level form in your component is a `FormGroup`. + +* [_FormArray_](../api/forms/index/FormArray-class.html "API Reference: FormArray") +tracks the value and validity state of a numerically indexed _array_ of `AbstractControl` instances. + +You'll learn more about these classes as you work through this guide. + +### Style the app +You used bootstrap CSS classes in the template HTML of both the `AppComponent` and the `HeroDetailComponent`. +Add the `bootstrap` _CSS stylesheet_ to the head of `index.html`: + + +{@example 'reactive-forms/ts/src/index.html' region='bootstrap'} + +Now that everything is wired up, the browser should display something like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/just-formcontrol.png" width="400px" alt="Single FormControl"> </img> +</figure> + + + +{@a formgroup} +## Add a FormGroup +Usually, if you have multiple *FormControls*, you'll want to register +them within a parent `FormGroup`. +This is simple to do. To add a `FormGroup`, add it to the imports section +of `hero-detail.component.ts`: + + +{@example 'reactive-forms/ts/src/app/hero-detail-2.component.ts' region='imports'} + +In the class, wrap the `FormControl` in a `FormGroup` called `heroForm` as follows: + + +{@example 'reactive-forms/ts/src/app/hero-detail-2.component.ts' region='v2'} + +Now that you've made changes in the class, they need to be reflected in the +template. Update `hero-detail.component.html` by replacing it with the following. + + +{@example 'reactive-forms/ts/src/app/hero-detail-2.component.html' region='basic-form'} + +Notice that now the single input is in a `form` element. The `novalidate` +attribute in the `<form>` element prevents the browser +from attempting native HTML validations. + +`formGroup` is a reactive form directive that takes an existing +`FormGroup` instance and associates it with an HTML element. +In this case, it associates the `FormGroup` you saved as +`heroForm` with the form element. + +Because the class now has a `FormGroup`, you must update the template +syntax for associating the input with the corresponding +`FormControl` in the component class. +Without a parent `FormGroup`, +`[formControl]="name"` worked earlier because that directive +can stand alone, that is, it works without being in a `FormGroup`. +With a parent `FormGroup`, the `name` input needs the syntax +`formControlName=name` in order to be associated +with the correct `FormControl` +in the class. This syntax tells Angular to look for the parent +`FormGroup`, in this case `heroForm`, and then _inside_ that group +to look for a `FormControl` called `name`. + +Disregard the `form-group` _CSS_ class. It belongs to the +<a href="http://getbootstrap.com/" target="_blank" title="Bootstrap CSS">Bootstrap CSS library</a>, +not Angular. +Like the `form-control` class, it _styles_ the form +but in no way impacts its logic. + +The form looks great. But does it work? +When the user enters a name, where does the value go? + + +{@a json} +## Taking a look at the form model + +The value goes into the **_form model_** that backs the group's `FormControls`. +To see the form model, add the following line after the +closing `form` tag in the `hero-detail.component.html`: + + +{@example 'reactive-forms/ts/src/app/hero-detail-3.component.html' region='form-value-json'} + +The `heroForm.value` returns the _form model_. +Piping it through the `JsonPipe` renders the model as JSON in the browser: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/json-output.png" width="400px" alt="JSON output"> </img> +</figure> + +The initial `name` property value is the empty string. +Type into the _name_ input box and watch the keystokes appear in the JSON. + + +Great! You have the basics of a form. + +In real life apps, forms get big fast. +`FormBuilder` makes form development and maintenance easier. + + + + +{@a formbuilder} +## Introduction to _FormBuilder_ + +The `FormBuilder` class helps reduce repetition and +clutter by handling details of control creation for you. + +To use `FormBuilder`, you need to import it into `hero-detail.component.ts`: + +{@example 'reactive-forms/ts/src/app/hero-detail-3a.component.ts' region='imports'} + +Use it now to refactor the `HeroDetailComponent` into something that's a little easier to read and write, +by following this plan: + +* Explicitly declare the type of the `heroForm` property to be `FormGroup`; you'll initialize it later. +* Inject a `FormBuilder` into the constructor. +* Add a new method that uses the `FormBuilder` to define the `heroForm`; call it `createForm`. +* Call `createForm` in the constructor. + +The revised `HeroDetailComponent` looks like this: + +{@example 'reactive-forms/ts/src/app/hero-detail-3a.component.ts' region='v3a'} + +`FormBuilder.group` is a factory method that creates a `FormGroup`.   +`FormBuilder.group` takes an object whose keys and values are `FormControl` names and their definitions. +In this example, the `name` control is defined by its initial data value, an empty string. + +Defining a group of controls in a single object makes for a compact, readable style. +It beats writing an equivalent series of `new FormControl(...)` statements. + + +{@a validators} +### Validators.required +Though this guide doesn't go deeply into validations, here is one example that +demonstrates the simplicity of using `Validators.required` in reactive forms. + +First, import the `Validators` symbol. + +{@example 'reactive-forms/ts/src/app/hero-detail-3.component.ts' region='imports'} + +To make the `name` `FormControl` required, replace the `name` +property in the `FormGroup` with an array. +The first item is the initial value for `name`; +the second is the required validator, `Validators.required`. + + +{@example 'reactive-forms/ts/src/app/hero-detail-3.component.ts' region='required'} + + +Reactive validators are simple, composable functions. +Configuring validation is harder in template-driven forms where you must wrap validators in a directive. Update the diagnostic message at the bottom of the template to display the form's validity status. + + +{@example 'reactive-forms/ts/src/app/hero-detail-3.component.html' region='form-value-json'} + +The browser displays the following: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl"> </img> +</figure> + +`Validators.required` is working. The status is `INVALID` because the input box has no value. +Type into the input box to see the status change from `INVALID` to `VALID`. + +In a real app, you'd replace the diagnosic message with a user-friendly experience. +Using `Validators.required` is optional for the rest of the guide. +It remains in each of the following examples with the same configuration. + +For more on validating Angular forms, see the +[Form Validation](../cookbook/form-validation.html) guide. +### More FormControls +A hero has more than a name. +A hero has an address, a super power and sometimes a sidekick too. + +The address has a state property. The user will select a state with a `<select>` box and you'll populate +the `<option>` elements with states. So import `states` from `data-model.ts`. + +{@example 'reactive-forms/ts/src/app/hero-detail-4.component.ts' region='imports'} + +Declare the `states` property and add some address `FormControls` to the `heroForm` as follows. + + +{@example 'reactive-forms/ts/src/app/hero-detail-4.component.ts' region='v4'} + +Then add corresponding markup in `hero-detail.component.html` +within the `form` element. + + +{@example 'reactive-forms/ts/src/app/hero-detail-4.component.html'} + + + +~~~ {.alert.is-helpful} + +*Reminder*: Ignore the many mentions of `form-group`, +`form-control`, `center-block`, and `checkbox` in this markup. +Those are _bootstrap_ CSS classes that Angular itself ignores. +Pay attention to the `formGroupName` and `formControlName` attributes. +They are the Angular directives that bind the HTML controls to the +Angular `FormGroup` and `FormControl` properties in the component class. + + +~~~ + +The revised template includes more text inputs, a select box for the `state`, radio buttons for the `power`, +and a checkbox for the `sidekick`. + +You must bind the option's value property with `[value]="state"`. +If you do not bind the value, the select shows the first option form the data model. + +The component _class_ defines control properties without regard for their representation in the template. +You define the `state`, `power`, and `sidekick` controls the same way you defined the `name` control. +You tie these controls to the template HTML elements in the same way, +specifiying the `FormControl` name with the `formControlName` directive. + +See the API reference for more information about +[radio buttons](../api/forms/index/RadioControlValueAccessor-directive.html "API: RadioControlValueAccessor"), +[selects](../api/forms/index/SelectControlValueAccessor-directive.html "API: SelectControlValueAccessor"), and +[checkboxes](../api/forms/index/CheckboxControlValueAccessor-directive.html "API: CheckboxControlValueAccessor"). + + + +{@a grouping} +### Nested FormGroups + +This form is getting big and unwieldy. You can group some of the related `FormControls` +into a nested `FormGroup`. The `street`, `city`, `state`, and `zip` are properties +that would make a good _address_ `FormGroup`. +Nesting groups and controls in this way allows you to +mirror the hierarchical structure of the data model +and helps track validation and state for related sets of controls. + +You used the `FormBuilder` to create one `FormGroup` in this component called `heroForm`. +Let that be the parent `FormGroup`. +Use `FormBuilder` again to create a child `FormGroup` that encapsulates the address controls; +assign the result to a new `address` property of the parent `FormGroup`. + +{@example 'reactive-forms/ts/src/app/hero-detail-5.component.ts' region='v5'} + +You’ve changed the structure of the form controls in the component class; +you must make corresponding adjustments to the component template. + +In `hero-detail.component.html`, wrap the address-related `FormControls` in a `div`. +Add a `formGroupName` directive to the `div` and bind it to `"address"`. +That's the property of the _address_ child `FormGroup` within the parent `FormGroup` called `heroForm`. + +To make this change visually obvious, slip in an `<h4>` header near the top with the text, _Secret Lair_. +The new _address_ HTML looks like this: + + +{@example 'reactive-forms/ts/src/app/hero-detail-5.component.html' region='add-group'} + +After these changes, the JSON output in the browser shows the revised _form model_ +with the nested address `FormGroup`: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/address-group.png" width="400px" alt="JSON output"> </img> +</figure> + +Great! You’ve made a group and you can see that the template +and the form model are talking to one another. + + + +{@a properties} +## Inspect _FormControl_ Properties +At the moment, you're dumping the entire form model onto the page. +Sometimes you're interested only in the state of one particular `FormControl`. + +You can inspect an individual `FormControl` within a form by extracting it with the `.get()` method. +You can do this _within_ the component class or display it on the +page by adding the following to the template, +immediately after the `{{form.value | json}}` interpolation as follows: + + +{@example 'reactive-forms/ts/src/app/hero-detail-5.component.html' region='inspect-value'} + +To get the state of a `FormControl` that’s inside a `FormGroup`, use dot notation to path to the control. + + +{@example 'reactive-forms/ts/src/app/hero-detail-5.component.html' region='inspect-child-control'} + +You can use this technique to display _any_ property of a `FormControl` +such as one of the following: +<style> + td, th {vertical-align: top} +</style> + + +<table width="100%"> + + <col width="10%"> + + </col> + + + <col width="90%"> + + </col> + + + <tr> + + <th> + Property + </th> + + + <th> + Description + </th> + + + </tr> + + + <tr> + + <td> + <code>myControl.value</code> + </td> + + + <td> + the value of a `FormControl`. + </td> + + + </tr> + + + <tr> + + <td> + <code>myControl.status</code> + </td> + + + <td> + the validity of a `FormControl`. Possible values: `VALID`, + `INVALID`, `PENDING`, or `DISABLED`. + </td> + + + </tr> + + + <tr> + + <td> + <code>myControl.pristine</code> + </td> + + + <td> + `true` if the user has _not_ changed the value in the UI. + Its opposite is `myControl.dirty`. + </td> + + + </tr> + + + <tr> + + <td> + <code>myControl.untouched</code> + </td> + + + <td> + `true` if the control user has not yet entered the HTML control + and triggered its blur event. Its opposite is `myControl.touched`. + + </td> + + + </tr> + + +</table> + +Learn about other `FormControl` properties in the +[_AbstractControl_](../api/forms/index/AbstractControl-class.html) API reference. + +One common reason for inspecting `FormControl` properties is to +make sure the user entered valid values. +Read more about validating Angular forms in the +[Form Validation](../cookbook/form-validation.html) guide. + + + +{@a data-model-form-model} +## The _data model_ and the _form model_ + +At the moment, the form is displaying empty values. +The `HeroDetailComponent` should display values of a hero, +possibly a hero retrieved from a remote server. + +In this app, the `HeroDetailComponent` gets its hero from a parent `HeroListComponent` + +The `hero` from the server is the **_data model_**. +The `FormControl` structure is the **_form model_**. + +The component must copy the hero values in the _data model_ into the _form model_. +There are two important implications: + +1. The developer must understand how the properties of the _data model_ +map to the properties of the _form model_. + +2. User changes flow from the DOM elements to the _form model_, not to the _data model_. +The form controls never update the _data model_. + +The _form_ and _data_ model structures need not match exactly. +You often present a subset of the _data model_ on a particular screen. +But it makes things easier if the shape of the _form model_ is close to the shape of the _data model_. + +In this `HeroDetailComponent`, the two models are quite close. + +Recall the definition of `Hero` in `data-model.ts`: + +{@example 'reactive-forms/ts/src/app/data-model.ts' region='model-classes'} + +Here, again, is the component's `FormGroup` definition. + + +{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='hero-form-model'} + +There are two significant differences between these models: + +1. The `Hero` has an `id`. The form model does not because you generally don't show primary keys to users. + +1. The `Hero` has an array of addresses. This form model presents only one address, +a choice [revisited below](#form-array "Form arrays"). + +Nonetheless, the two models are pretty close in shape and you'll see in a moment how this alignment facilitates copying the _data model_ properties +to the _form model_ with the `patchValue` and `setValue` methods. +Take a moment to refactor the _address_ `FormGroup` definition for brevity and clarity as follows: + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='address-form-group'} + +Also be sure to update the import from `data-model` so you can reference the `Hero` class: + +{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='import-hero'} + + + + +{@a set-data} +## Populate the form model with _setValue_ and _patchValue_ +Previously you created a control and initialized its value at the same time. +You can also initialize or reset the values _later_ with the +`setValue` and `patchValue` methods. + +### _setValue_ +With **`setValue`**, you assign _every_ form control value _at once_ +by passing in a data object whose properties exactly match the _form model_ behind the `FormGroup`. + + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='set-value'} + +The `setValue` method checks the data object thoroughly before assigning any form control values. + +It will not accept a data object that doesn't match the FormGroup structure or is +missing values for any control in the group. This way, it can return helpful +error messages if you have a typo or if you've nested controls incorrectly. +`patchValue` will fail silently. + +On the other hand,`setValue` will catch +the error and report it clearly. + +Notice that you can _almost_ use the entire `hero` as the argument to `setValue` +because its shape is similar to the component's `FormGroup` structure. + +You can only show the hero's first address and you must account for the possibility that the `hero` has no addresses at all. +This explains the conditional setting of the `address` property in the data object argument: + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='set-value-address'} + +### _patchValue_ +With **`patchValue`**, you can assign values to specific controls in a `FormGroup` +by supplying an object of key/value pairs for just the controls of interest. + +This example sets only the form's `name` control. + +{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='patch-value'} + +With **`patchValue`** you have more flexibility to cope with wildly divergent data and form models. +But unlike `setValue`, `patchValue` cannot check for missing control +values and does not throw helpful errors. + +### When to set form model values (_ngOnChanges_) + +Now you know _how_ to set the _form model_ values. But _when_ do you set them? +The answer depends upon when the component gets the _data model_ values. + +The `HeroDetailComponent` in this reactive forms sample is nested within a _master/detail_ `HeroListComponent` ([discussed below](#hero-list)). +The `HeroListComponent` displays hero names to the user. +When the user clicks on a hero, the list component passes the selected hero into the `HeroDetailComponent` +by binding to its `hero` input property. + + +{@example 'reactive-forms/ts/src/app/hero-list.component.1.html'} + +In this approach, the value of `hero` in the `HeroDetailComponent` changes +every time the user selects a new hero. +You should call _setValue_ in the [ngOnChanges](lifecyle-hooks.html#onchanges) +hook, which Angular calls whenever the input `hero` property changes +as the following steps demonstrate. + +First, import the `ngOnChanges` and `import` symbol in `hero-detail.component.ts`. + + +{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='import-input'} + +Add the `hero` input property. + +{@example 'reactive-forms/ts/src/app/hero-detail-6.component.ts' region='hero'} + +Add the `ngOnChanges` method to the class as follows: + + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='ngOnChanges-1'} + +### _reset_ the form flags + +You should reset the form when the hero changes so that +control values from the previous hero are cleared and +status flags are restored to the _pristine_ state. +You could call `reset` at the top of `ngOnChanges` like this. + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='reset'} + +The `reset` method has an optional `state` value so you can reset the flags _and_ the control values at the same. +Internally, `reset` passes the argument to `setValue`. +A little refactoring and `ngOnChanges` becomes this: + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='ngOnChanges'} + + + +{@a hero-list} +### Create the _HeroListComponent_ and _HeroService_ + +The `HeroDetailComponent` is a nested sub-component of the `HeroListComponent` in a _master/detail_ view. +Together they look a bit like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/hero-list.png" width="420px" alt="HeroListComponent"> </img> +</figure> + +The `HeroListComponent` uses an injected `HeroService` to retrieve heroes from the server +and then presents those heroes to the user as a series of buttons. +The `HeroService` emulates an HTTP service. +It returns an `Observable` of heroes that resolves after a short delay, +both to simulate network latency and to indicate visually +the necessarily asynchronous nature of the application. + +When the user clicks on a hero, +the component sets its `selectedHero` property which +is bound to the `hero` input property of the `HeroDetailComponent`. +The `HeroDetailComponent` detects the changed hero and re-sets its form +with that hero's data values. + +A "Refresh" button clears the hero list and the current selected hero before refetching the heroes. + +The remaining `HeroListComponent` and `HeroService` implementation details are not relevant to understanding reactive forms. +The techniques involved are covered elsewhere in the documentation, including the _Tour of Heroes_ +[here](../tutorial/toh-pt3.html "ToH: Multiple Components") and [here](../tutorial/toh-pt4.html "ToH: Services"). + +If you're coding along with the steps in this reactive forms tutorial, +create the pertinent files based on the +[source code displayed below](#source-code "Reactive Forms source code"). +Notice that `hero-list.component.ts` and `hero-list.component.ts` +import `Observable` and `finally` from `rxjs`. +Then return here to learn about _form array_ properties. + + + +{@a form-array} +## Use _FormArray_ to present an array of _FormGroups_ +So far, you've seen `FormControls` and `FormGroups`. +A `FormGroup` is a named object whose property values are `FormControls` and other `FormGroups`. + +Sometimes you need to present an arbitrary number of controls or groups. +For example, a hero may have zero, one, or any number of addresses. + +The `Hero.addresses` property is an array of `Address` instances. +An _address_ `FormGroup` can display one `Address`. +An Angular `FormArray` can display an array of _address_ `FormGroups`. + +To get access to the `FormArray` class, import it into `hero-detail.component.ts`: + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='imports'} + +To _work_ with a `FormArray` you do the following: +1. Define the items (`FormControls` or `FormGroups`) in the array. +1. Initialize the array with items created from data in the _data model_. +1. Add and remove items as the user requires. + +In this guide, you define a `FormArray` for `Hero.addresses` and +let the user add or modify addresses (removing addresses is your homework). + +You’ll need to redefine the form model in the `HeroDetailComponent` constructor, +which currently only displays the first hero address in an _address_ `FormGroup`. + +{@example 'reactive-forms/ts/src/app/hero-detail-7.component.ts' region='address-form-group'} + +### From _address_ to _secret lairs_ + +From the user's point of view, heroes don't have _addresses_. +_Addresses_ are for mere mortals. Heroes have _secret lairs_! +Replace the _address_ `FormGroup` definition with a _secretLairs_ `FormArray` definition: + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='secretLairs-form-array'} + + + +~~~ {.alert.is-helpful} + +Changing the form control name from `address` to `secretLairs` drives home an important point: +the _form model_ doesn't have to match the _data model_. + +Obviously there has to be a relationship between the two. +But it can be anything that makes sense within the application domain. + +_Presentation_ requirements often differ from _data_ requirements. +The reactive forms approach both emphasizes and facilitates this distinction. + + +~~~ + +### Initialize the "secretLairs" _FormArray_ + +The default form displays a nameless hero with no addresses. + +You need a method to populate (or repopulate) the _secretLairs_ with actual hero addresses whenever +the parent `HeroListComponent` sets the `HeroListComponent.hero` input property to a new `Hero`. + +The following `setAddresses` method replaces the _secretLairs_ `FormArray` with a new `FormArray`, +initialized by an array of hero address `FormGroups`. + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='set-addresses'} + +Notice that you replace the previous `FormArray` with the **`FormGroup.setControl` method**, not with `setValue`. +You're replacing a _control_, not the _value_ of a control. + +Notice also that the _secretLairs_ `FormArray` contains **`FormGroups`**, not `Addresses`. + +### Get the _FormArray_ +The `HeroDetailComponent` should be able to display, add, and remove items from the _secretLairs_ `FormArray`. + +Use the `FormGroup.get` method to acquire a reference to that `FormArray`. +Wrap the expression in a `secretLairs` convenience property for clarity and re-use. + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='get-secret-lairs'} + +### Display the _FormArray_ + +The current HTML template displays a single _address_ `FormGroup`. +Revise it to display zero, one, or more of the hero's _address_ `FormGroups`. + +This is mostly a matter of wrapping the previous template HTML for an address in a `<div>` and +repeating that `<div>` with `*ngFor`. + +The trick lies in knowing how to write the `*ngFor`. There are three key points: + +1. Add another wrapping `<div>`, around the `<div>` with `*ngFor`, and +set its `formArrayName` directive to `"secretLairs"`. +This step establishes the _secretLairs_ `FormArray` as the context for form controls in the inner, repeated HTML template. + +1. The source of the repeated items is the `FormArray.controls`, not the `FormArray` itself. +Each control is an _address_ `FormGroup`, exactly what the previous (now repeated) template HTML expected. + +1. Each repeated `FormGroup` needs a unique `formGroupName` which must be the index of the `FormGroup` in the `FormArray`. +You'll re-use that index to compose a unique label for each address. + +Here's the skeleton for the _secret lairs_ section of the HTML template: + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.html' region='form-array-skeleton'} + +Here's the complete template for the _secret lairs_ section: + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.html' region='form-array'} + +### Add a new lair to the _FormArray_ + +Add an `addLair` method that gets the _secretLairs_ `FormArray` and appends a new _address_ `FormGroup` to it. + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='add-lair'} + +Place a button on the form so the user can add a new _secret lair_ and wire it to the component's `addLair` method. + + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.html' region='add-lair'} + + + +~~~ {.alert.is-important} + +Be sure to **add the `type="button"` attribute**. +In fact, you should always specify a button's `type`. +Without an explict type, the button type defaults to "submit". +When you later add a _form submit_ action, every "submit" button triggers the submit action which +might do something like save the current changes. +You do not want to save changes when the user clicks the _Add a Secret Lair_ button. + + +~~~ + +### Try it! + +Back in the browser, select the hero named "Magneta". +"Magneta" doesn't have an address, as you can see in the diagnostic JSON at the bottom of the form. + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/addresses-array.png" width="400px" alt="JSON output of addresses array"> </img> +</figure> + +Click the "_Add a Secret Lair_" button. +A new address section appears. Well done! + +### Remove a lair + +This example can _add_ addresses but it can't _remove_ them. +For extra credit, write a `removeLair` method and wire it to a button on the repeating address HTML. + + + +{@a observe-control} +## Observe control changes + +Angular calls `ngOnChanges` when the user picks a hero in the parent `HeroListComponent`. +Picking a hero changes the `HeroDetailComponent.hero` input property. + +Angular does _not_ call `ngOnChanges` when the user modifies the hero's _name_ or _secret lairs_. +Fortunately, you can learn about such changes by subscribing to one of the form control properties +that raises a change event. + +These are properties, such as `valueChanges`, that return an RxJS `Observable`. +You don't need to know much about RxJS `Observable` to monitor form control values. + +Add the following method to log changes to the value of the _name_ `FormControl`. + +{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='log-name-change'} + +Call it in the constructor, after creating the form. + +{@example 'reactive-forms/ts/src/app/hero-detail-8.component.ts' region='ctor'} + +The `logNameChange` method pushes name-change values into a `nameChangeLog` array. +Display that array at the bottom of the component template with this `*ngFor` binding: + +{@example 'reactive-forms/ts/src/app/hero-detail.component.html' region='name-change-log'} + +Return to the browser, select a hero (e.g, "Magneta"), and start typing in the _name_ input box. +You should see a new name in the log after each keystroke. + +### When to use it + +An interpolation binding is the easier way to _display_ a name change. +Subscribing to an observable form control property is handy for triggering +application logic _within_ the component class. + + + +{@a save} +## Save form data + +The `HeroDetailComponent` captures user input but it doesn't do anything with it. +In a real app, you'd probably save those hero changes. +In a real app, you'd also be able to revert unsaved changes and resume editing. +After you implement both features in this section, the form will look like this: + +<figure class='image-display'> + <img src="/resources/images/devguide/reactive-forms/save-revert-buttons.png" width="389px" alt="Form with save & revert buttons"> </img> +</figure> + +### Save +In this sample application, when the user submits the form, +the `HeroDetailComponent` will pass an instance of the hero _data model_ +to a save method on the injected `HeroService`. + +{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='on-submit'} + +This original `hero` had the pre-save values. The user's changes are still in the _form model_. +So you create a new `hero` from a combination of original hero values (the `hero.id`) +and deep copies of the changed form model values, using the `prepareSaveHero` helper. + + +{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='prepare-save-hero'} + + +**Address deep copy** + +Had you assigned the `formModel.secretLairs` to `saveHero.addresses` (see line commented out), +the addresses in `saveHero.addresses` array would be the same objects +as the lairs in the `formModel.secretLairs`. +A user's subsequent changes to a lair street would mutate an address street in the `saveHero`. + +The `prepareSaveHero` method makes copies of the form model's `secretLairs` objects so that can't happen. +### Revert (cancel changes) +The user cancels changes and reverts the form to the original state by pressing the _Revert_ button. + +Reverting is easy. Simply re-execute the `ngOnChanges` method that built the _form model_ from the original, unchanged `hero` _data model_. + +{@example 'reactive-forms/ts/src/app/hero-detail.component.ts' region='revert'} + +### Buttons +Add the "Save" and "Revert" buttons near the top of the component's template: + +{@example 'reactive-forms/ts/src/app/hero-detail.component.html' region='buttons'} + +The buttons are disabled until the user "dirties" the form by changing a value in any of its form controls (`heroForm.dirty`). + +Clicking a button of type `"submit"` triggers the `ngSubmit` event which calls the component's `onSubmit` method. +Clicking the revert button triggers a call to the component's `revert` method. +Users now can save or revert changes. + +This is the final step in the demo. +Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker"></live-example>. + + +## Conclusion + +This page covered: + +- How to create a reactive form component and its corresponding template. +- How to use `FormBuilder` to simplify coding a reactive form. +- Grouping `FormControls`. +- Inspecting `FormControl` properties. +- Setting data with `patchValue` and `setValue`. +- Adding groups dynamically with `FormArray`. +- Observing changes to the value of a `FormControl`. +- Saving form changes. + + +{@a source-code} +The key files of the final version are as follows: + +<md-tab-group> + + <md-tab label="src/app/app.component.ts"> + {@example 'reactive-forms/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="src/app/app.module.ts"> + {@example 'reactive-forms/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="src/app/hero-detail.component.ts"> + {@example 'reactive-forms/ts/src/app/hero-detail.component.ts'} + </md-tab> + + + <md-tab label="src/app/hero-detail.component.html"> + {@example 'reactive-forms/ts/src/app/hero-detail.component.html'} + </md-tab> + + + <md-tab label="src/app/hero-list.component.html"> + {@example 'reactive-forms/ts/src/app/hero-list.component.html'} + </md-tab> + + + <md-tab label="src/app/hero-list.component.ts"> + {@example 'reactive-forms/ts/src/app/hero-list.component.ts'} + </md-tab> + + + <md-tab label="src/app/data-model.ts"> + {@example 'reactive-forms/ts/src/app/data-model.ts'} + </md-tab> + + + <md-tab label="src/app/hero.service.ts"> + {@example 'reactive-forms/ts/src/app/hero.service.ts'} + </md-tab> + + +</md-tab-group> + +You can download the complete source for all steps in this guide +from the <live-example title="Reactive Forms Demo in Plunker">Reactive Forms Demo</live-example> live example. \ No newline at end of file diff --git a/aio/content/guide/router.md b/aio/content/guide/router.md new file mode 100644 index 0000000000..35d15f5b2e --- /dev/null +++ b/aio/content/guide/router.md @@ -0,0 +1,2838 @@ +@title +Routing & Navigation + +@intro +Discover the basics of screen navigation with the Angular Router. + +@description +The Angular **`Router`** enables navigation from one [view](./glossary.html#view) to the next +as users perform application tasks. + +This guide covers the router's primary features, illustrating them through the evolution +of a small application that you can <live-example>run live in the browser</live-example>. + +## Overview + +The browser is a familiar model of application navigation: + +* Enter a URL in the address bar and the browser navigates to a corresponding page. +* Click links on the page and the browser navigates to a new page. +* Click the browser's back and forward buttons and the browser navigates + backward and forward through the history of pages you've seen. + +The Angular `Router` ("the router") borrows from this model. +It can interpret a browser URL as an instruction to navigate to a client-generated view. +It can pass optional parameters along to the supporting view component that help it decide what specific content to present. +You can bind the router to links on a page and it will navigate to +the appropriate application view when the user clicks a link. +You can navigate imperatively when the user clicks a button, selects from a drop box, +or in response to some other stimulus from any source. And the router logs activity +in the browser's history journal so the back and forward buttons work as well. + +You'll learn many router details in this guide which covers + +* Setting the [base href](#base-href) +* Importing from the [router library](#import) +* [Configuring the router](#route-config) +* Handling unmatched URLs with a [wildcard route](#wildcard-route) +* The [link parameters array](#link-parameters-array) that propels router navigation +* Setting the [default route](#default-route) where the application navigates at launch +* [Redirecting](#redirect) from one route to another +* Navigating when the user clicks a data-bound [RouterLink](#router-link) +* Navigating under [program control](#navigate) +* Retrieving information from the [route](#activated-route) +* [Animating](#route-animation) transitions for route components +* Navigating [relative](#relative-navigation) to the current URL +* Toggling css classes for the [active router link](#router-link-active) +* Embedding critical information in the URL with [route parameters](#route-parameters) +* Providing non-critical information in [optional route parameters](#optional-route-parameters) +* Refactoring routing into a [routing module](#routing-module) +* [Importing routing modules in the proper order](#routing-module-order) +* Add [child routes](#child-routing-component) under a feature section +* [Grouping child routes](#component-less-route) without a component +* Displaying [multiple routes](#named-outlets) in separate outlets +* Confirming or canceling navigation with [guards](#guards) + * [CanActivate](#can-activate-guard) to prevent navigation to a route + * [CanActivateChild](#can-activate-child-guard) to prevent navigation to a child route + * [CanDeactivate](#can-deactivate-guard) to prevent navigation away from the current route + * [Resolve](#resolve-guard) to pre-fetch data before activating a route + * [CanLoad](#can-load-guard) to prevent asynchronous routing +* Providing optional information across routes with [query parameters](#query-parameters) +* Jumping to anchor elements using a [fragment](#fragment) +* Loading feature areas [asynchronously](#asynchronous-routing) +* Preloading feature areas [during navigation](#preloading) +* Using a [custom strategy](#custom-preloading) to only preload certain features +* [Inspect the router's configuration](#inspect-config). +* Choosing the "HTML5" or "hash" [URL style](#browser-url-styles) + +## The Basics + +This guide proceeds in phases, marked by milestones, starting from a simple two-pager +and building toward a modular, multi-view design with child routes. + +An introduction to a few core router concepts will help orient you to the details that follow. +### *<base href>* + +Most routing applications should add a `<base>` element to the `index.html` as the first child in the `<head>` tag +to tell the router how to compose navigation URLs. + +If the `app` folder is the application root, as it is for the sample application, +set the `href` value *exactly* as shown here. +### Router imports + +The Angular Router is an optional service that presents a particular component view for a given URL. +It is not part of the Angular core. It is in its own library package, `@angular/router`. +Import what you need from it as you would from any other Angular package. + +You'll learn about more options in the [details below](#browser-url-styles).### Configuration + +A routed Angular application has one, singleton instance of the *`Router`* service. +When the browser's URL changes, that router looks for a corresponding `Route` +from which it can determine the component to display. + +A router has no routes until you configure it. +The following example creates four route definitions, configures the router via the `RouterModule.forRoot` method, +and adds the result to the `AppModule`'s `imports` array. + + +{@a example-config} +The `appRoutes` array of *routes* describes how to navigate. +Pass it to the `RouterModule.forRoot` method in the module `imports` to configure the router. + +Each `Route` maps a URL `path` to a component. +There are _no leading slashes_ in the _path_. +The router parses and builds the final URL for you, +allowing you to use both relative and "absolute" paths when navigating between application views. + +The `:id` in the first route is a token for a route parameter. In a URL such as `/hero/42`, "42" +is the value of the `id` parameter. The corresponding `HeroDetailComponent` +will use that value to find and present the hero whose `id` is 42. +You'll learn more about route parameters later in this guide. + +The `data` property in the third route is a place to store arbitrary data associated with +this specific route. The data property is accessible within each activated route. Use it to store +items such as page titles, breadcrumb text, and other read-only, _static_ data. +You'll use the [resolve guard](#resolve-guard) to retrieve _dynamic_ data later in the guide. + +The `empty path` in the fourth route represents the default path for the application, +the place to go when the path in the URL is empty, as it typically is at the start. +This default route redirects to the route for the `/heroes` URL and, therefore, will display the `HeroesListComponent`. + +The `**` path in the last route is a **wildcard**. The router will select this route +if the requested URL doesn't match any paths for routes defined earlier in the configuration. +This is useful for displaying a "404 - Not Found" page or redirecting to another route. + +**The order of the routes in the configuration matters** and this is by design. The router uses a **first-match wins** +strategy when matching routes, so more specific routes should be placed above less specific routes. +In the configuration above, routes with a static path are listed first, followed by an empty path route, +that matches the default route. +The wildcard route comes last because it matches _every URL_ and should be selected _only_ if no other routes are matched first. +### Router outlet + +Given this configuration, when the browser URL for this application becomes `/heroes`, +the router matches that URL to the route path `/heroes` and displays the `HeroListComponent` +_after_ a `RouterOutlet` that you've placed in the host view's HTML. + +<code-example language="html"> + <router-outlet></router-outlet> + <!-- Routed views go here --> + +</code-example> + +### Router links + +Now you have routes configured and a place to render them, but +how do you navigate? The URL could arrive directly from the browser address bar. +But most of the time you navigate as a result of some user action such as the click of +an anchor tag. + +Consider the following template: +The `RouterLink` directives on the anchor tags give the router control over those elements. +The navigation paths are fixed, so you can assign a string to the `routerLink` (a "one-time" binding). + +Had the navigation path been more dynamic, you could have bound to a template expression that +returned an array of route link parameters (the _link parameters array_). +The router resolves that array into a complete URL. + +The **`RouterLinkActive`** directive on each anchor tag helps visually distinguish the anchor for the currently selected "active" route. +The router adds the `active` CSS class to the element when the associated *RouterLink* becomes active. +You can add this directive to the anchor or to its parent element. +### Router state + +After the end of each successful navigation lifecycle, the router builds a tree of `ActivatedRoute` objects +that make up the current state of the router. You can access the current `RouterState` from anywhere in the +application using the `Router` service and the `routerState` property. + +Each `ActivatedRoute` in the `RouterState` provides methods to traverse up and down the route tree +to get information from parent, child and sibling routes. +### Summary + +The application has a configured router. +The shell component has a `RouterOutlet` where it can display views produced by the router. +It has `RouterLink`s that users can click to navigate via the router. + +Here are the key `Router` terms and their meanings: +<style> + td, th {vertical-align: top} +</style> + + +<table> + + <tr> + + <th> + Router Part + </th> + + + <th> + Meaning + </th> + + + </tr> + + + <tr> + + <td> + <code>Router</code> + </td> + + + <td> + Displays the application component for the active URL. + Manages navigation from one component to the next. + </td> + + + </tr> + + + <tr> + + <td> + <code>RouterModule</code> + </td> + + + <td> + A separate Angular module that provides the necessary service providers + and directives for navigating through application views. + </td> + + + </tr> + + + <tr> + + <td> + <code>Routes</code> + </td> + + + <td> + Defines an array of Routes, each mapping a URL path to a component. + </td> + + + </tr> + + + <tr> + + <td> + <code>Route</code> + </td> + + + <td> + Defines how the router should navigate to a component based on a URL pattern. + Most routes consist of a path and a component type. + </td> + + + </tr> + + + <tr> + + <td> + <code>RouterOutlet</code> + </td> + + + <td> + The directive (<code><router-outlet></code>) that marks where the router should display a view. + </td> + + + </tr> + + + <tr> + + <td> + <code>RouterLink</code> + </td> + + + <td> + The directive for binding a clickable HTML element to + a route. Clicking an element with a <code>routerLink</code> directive + that is bound to a <i>string</i> or a <i>link parameters array</i> triggers a navigation. + </td> + + + </tr> + + + <tr> + + <td> + <code>RouterLinkActive</code> + </td> + + + <td> + The directive for adding/removing classes from an HTML element when an associated + routerLink contained on or inside the element becomes active/inactive. + </td> + + + </tr> + + + <tr> + + <td> + <code>ActivatedRoute</code> + </td> + + + <td> + A service that is provided to each route component that contains route specific + information such as route parameters, static data, resolve data, global query params and the global fragment. + </td> + + + </tr> + + + <tr> + + <td> + <code>RouterState</code> + </td> + + + <td> + The current state of the router including a tree of the currently activated + routes together with convenience methods for traversing the route tree. + </td> + + + </tr> + + + <tr> + + <td> + <b><i>Link parameters array</i></b> + </td> + + + <td> + An array that the router interprets as a routing instruction. + You can bind that array to a <code>RouterLink</code> or pass the array as an argument to + the <code>Router.navigate</code> method. + </td> + + + </tr> + + + <tr> + + <td> + <b><i>Routing component</i></b> + </td> + + + <td> + An Angular component with a <code>RouterOutlet</code> that displays views based on router navigations. + + </td> + + + </tr> + + +</table> + + +## The sample application + +This guide describes development of a multi-page routed sample application. +Along the way, it highlights design decisions and describes key features of the router such as: + +* organizing the application features into modules +* navigating to a component (*Heroes* link to "Heroes List") +* including a route parameter (passing the Hero `id` while routing to the "Hero Detail") +* child routes (the *Crisis Center* has its own routes) +* the `CanActivate` guard (checking route access) +* the `CanActivateChild` guard (checking child route access) +* the `CanDeactivate` guard (ask permission to discard unsaved changes) +* the `Resolve` guard (pre-fetching route data) +* lazy loading feature modules +* the `CanLoad` guard (check before loading feature module assets) + +The guide proceeds as a sequence of milestones as if you were building the app step-by-step. +But, it is not a tutorial and it glosses over details of Angular application construction +that are more thoroughly covered elsewhere in the documentation. + +The full source for the final version of the app can be seen and downloaded from the <live-example></live-example>. +### The sample application in action + +Imagine an application that helps the _Hero Employment Agency_ run its business. +Heroes need work and the agency finds crises for them to solve. + +The application has three main feature areas: + +1. A *Crisis Center* for maintaining the list of crises for assignment to heroes. +1. A *Heroes* area for maintaining the list of heroes employed by the agency. +1. An *Admin* area to manage the list of crises and heroes. + +Try it by clicking on this <live-example title="Hero Employment Agency Live Example">live example link</live-example>. + +Once the app warms up, you'll see a row of navigation buttons +and the *Heroes* view with its list of heroes. + +<figure class='image-display'> + <img src='/resources/images/devguide/router/hero-list.png' alt="Hero List" width="250"> </img> +</figure> + +Select one hero and the app takes you to a hero editing screen. +<figure class='image-display'> + <img src='/resources/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250"> </img> +</figure> + +Alter the name. +Click the "Back" button and the app returns to the heroes list which displays the changed hero name. +Notice that the name change took effect immediately. + +Had you clicked the browser's back button instead of the "Back" button, +the app would have returned you to the heroes list as well. +Angular app navigation updates the browser history as normal web navigation does. + +Now click the *Crisis Center* link for a list of ongoing crises. + +<figure class='image-display'> + <img src='/resources/images/devguide/router/crisis-center-list.png' alt="Crisis Center List" width="250"> </img> +</figure> + +Select a crisis and the application takes you to a crisis editing screen. +The _Crisis Detail_ appears in a child view on the same page, beneath the list. + +Alter the name of a crisis. +Notice that the corresponding name in the crisis list does _not_ change. + +<figure class='image-display'> + <img src='/resources/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail" width="250"> </img> +</figure> + +Unlike *Hero Detail*, which updates as you type, +*Crisis Detail* changes are temporary until you either save or discard them by pressing the "Save" or "Cancel" buttons. +Both buttons navigate back to the *Crisis Center* and its list of crises. + +***Do not click either button yet***. +Click the browser back button or the "Heroes" link instead. + +Up pops a dialog box. + +<figure class='image-display'> + <img src='/resources/images/devguide/router/confirm-dialog.png' alt="Confirm Dialog" width="250"> </img> +</figure> + +You can say "OK" and lose your changes or click "Cancel" and continue editing. + +Behind this behavior is the router's `CanDeactivate` guard. +The guard gives you a chance to clean-up or ask the user's permission before navigating away from the current view. + +The `Admin` and `Login` buttons illustrate other router capabilities to be covered later in the guide. +This short introduction will do for now. + +Proceed to the first application milestone. + +## Milestone 1: Getting started with the router + +Begin with a simple version of the app that navigates between two empty views. +<figure class='image-display'> + <img src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" width="250"> </img> +</figure> + + + +{@a base-href} +### Set the *<base href>* + +The router uses the browser's +<a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries" target="_blank" title="HTML5 browser history push-state">history.pushState</a> +for navigation. Thanks to `pushState`, you can make in-app URL paths look the way you want them to +look, e.g. `localhost:3000/crisis-center`. The in-app URLs can be indistinguishable from server URLs. + +Modern HTML 5 browsers were the first to support `pushState` which is why many people refer to these URLs as +"HTML 5 style" URLs. + +HTML 5 style navigation is the router default. +In the [Browser URL Styles](#browser-url-styles) Appendix, +learn why HTML 5 style is preferred, how to adjust its behavior, and how to switch to the +older hash (#) style, if necessary. +You must **add a +<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base" target="_blank" title="base href"><base href> element</a>** +to the app's `index.html` for `pushState` routing to work. +The browser uses the base `href` value to prefix *relative* URLs when referencing +CSS files, scripts, and images. + +Add the base element just after the `<head>` tag. +If the `app` folder is the application root, as it is for this application, +set the `href` value in **`index.html`** *exactly* as shown here. + + +~~~ {.callout.is-important} + + +<header> + Live example note +</header> + +A live coding environment like Plunker sets the application base address dynamically so you can't specify a fixed address. +That's why the example code replaces the `<base href...>` with a script that writes the `<base>` tag on the fly. + +<code-example language="html"> + <script>document.write('<base href="' + document.location + '" />');</script> + +</code-example> + +You should only need this trick for the live example, not production code. + + +~~~ + + + +{@a import} +### Configure the routes for the Router + +Begin by importing some symbols from the router library. +The Router is in its own `@angular/router` package. +It's not part of the Angular core. The router is an optional service because not all applications +need routing and, depending on your requirements, you may need a different routing library. + +You teach the router how to navigate by configuring it with routes. + + +{@a route-config} +#### Define routes + +A router must be configured with a list of route definitions. + +The first configuration defines an array of two routes with simple paths leading to the +`CrisisListComponent` and `HeroListComponent` components. + +Each definition translates to a [Route](../api/router/index/Route-interface.html) object which has a +`path`, the URL path segment for this route, and a +`component`, the component associated with this route. + +The router draws upon its registry of definitions when the browser URL changes +or when application code tells the router to navigate along a route path. + +In simpler terms, you might say this of the first route: + +- When the browser's location URL changes to match the path segment `/crisis-center`, then +the router activates an instance of the `CrisisListComponent` and displays its view. + +- When the application requests navigation to the path `/crisis-center`, the router +activates an instance of `CrisisListComponent`, displays its view, and updates the +browser's address location and history with the URL for that path. +Here is the first configuration. Pass the array of routes to the `RouterModule.forRoot` method. +It returns a module, containing the configured `Router` service provider, plus other providers that the routing library requires. +Once the application is bootstrapped, the `Router` performs the initial navigation based on the current browser URL. + +Adding the configured `RouterModule` to the `AppModule` is sufficient for simple route configurations. +As the application grows, you'll want to refactor the routing configuration into a separate file +and create a **[Routing Module](#routing-module)**, a special type of `Service Module` dedicated for the purpose +of routing in feature modules. +Providing the `RouterModule` in the `AppModule` makes the Router available everywhere in the application. + + +{@a shell} +### The *AppComponent* shell + +The root `AppComponent` is the application shell. It has a title, a navigation bar with two links, +and a *router outlet* where the router swaps views on and off the page. Here's what you get: + +<figure class='image-display'> + <img src='/resources/images/devguide/router/shell-and-outlet.png' alt="Shell" width="300"> </img> +</figure> + + + +{@a shell-template} +The corresponding component template looks like this: + + +{@a router-outlet} +### *RouterOutlet* + +The `RouterOutlet` is a directive from the router library that marks +the spot in the template where the router should display the views for that outlet. + +The router adds the `<router-outlet>` element to the DOM +and subsequently inserts the navigated view element +immediately _after_ the `<router-outlet>`. + + +{@a router-link} +### *RouterLink* binding + +Above the outlet, within the anchor tags, you see +[attribute bindings](template-syntax.html#attribute-binding) to +the `RouterLink` directive that look like `routerLink="..."`. + +The links in this example each have a string path, the path of a route that +you configured earlier. There are no route parameters yet. + +You can also add more contextual information to the `RouterLink` by providing query string parameters +or a URL fragment for jumping to different areas on the page. Query string parameters +are provided through the `[queryParams]` binding which takes an object (e.g. `{ name: 'value' }`), while the URL fragment +takes a single value bound to the `[fragment]` input binding. +Learn about the how you can also use the _link parameters array_ in the [appendix below](#link-parameters-array). + + +{@a router-link-active} +### *RouterLinkActive* binding + +On each anchor tag, you also see [Property Bindings](template-syntax.html#property-binding) to +the `RouterLinkActive` directive that look like `routerLinkActive="..."`. + +The template expression to the right of the equals (=) contains a space-delimited string of CSS classes +that the Router will add when this link is active (and remove when the link is inactive). +You can also set the `RouterLinkActive` directive to a string of classes such as `[routerLinkActive]="active fluffy"` +or bind it to a component property that returns such a string. + +The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`. +This cascades down through each level of the route tree, so parent and child router links can be active at the same time. +To override this behavior, you can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression. +By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL. + + +{@a router-directives} +### *Router directives* + +`RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives provided by the Angular `RouterModule` package. +They are readily available for you to use in the template. + +The current state of `app.component.ts` looks like this: +### Wildcard route + +You've created two routes in the app so far, one to `/crisis-center` and the other to `/heroes`. +Any other URL causes the router to throw an error and crash the app. + +Add a **wildcard** route to intercept invalid URLs and handle them gracefully. +A _wildcard_ route has a path consisting of two asterisks. It matches _every_ URL. +The router will select _this_ route if it can't match a route earlier in the configuration. +A wildcard route can navigate to a custom "404 Not Found" component or [redirect](#redirect) to an existing route. + +The router selects the route with a [_first match wins_](#example-config) strategy. +Wildcard routes are the least specific routes in the route configuration. +Be sure it is the _last_ route in the configuration. +To test this feature, add a button with a `RouterLink` to the `HeroListComponent` template and set the link to `"/sidekicks"`. The application will fail if the user clicks that button because you haven't defined a `"/sidekicks"` route yet. + +Instead of adding the `"/sidekicks"` route, define a `wildcard` route instead and have it navigate to a simple `PageNotFoundComponent`.Create the `PageNotFoundComponent` to display when users visit invalid URLs.As with the other components, add the `PageNotFoundComponent` to the `AppModule` declarations. + +Now when the user visits `/sidekicks`, or any other invalid URL, the browser displays the "Page not found". +The browser address bar continues to point to the invalid URL. + + + +{@a default-route} +### The _default_ route to heroes + +When the application launches, the initial URL in the browser bar is something like: + +<code-example> + localhost:3000 + +</code-example> + +That doesn't match any of the configured routes which means that the application won't display any component when it's launched. +The user must click one of the links to trigger a navigation and display a component. + +It would be nicer if the application had a **default route** that displayed the list of heroes immediately, +just as it will when the user clicks the "Heroes" link or pastes `localhost:3000/heroes` into the address bar. + + +{@a redirect} +### Redirecting routes + +The preferred solution is to add a `redirect` route that translates the initial relative URL (`''`) +to the desired default path (`/heroes`). The browser address bar shows `.../heroes` as if you'd navigated there directly. + +Add the default route somewhere _above_ the wildcard route. +It's just above the wildcard route in the following excerpt showing the complete `appRoutes` for this milestone. +A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route. +The router throws an error if you don't. +In this app, the router should select the route to the `HeroListComponent` only when the *entire URL* matches `''`, +so set the `pathMatch` value to `'full'`. + +Technically, `pathMatch = 'full'` results in a route hit when the *remaining*, unmatched segments of the URL match `''`. +In this example, the redirect is in a top level route so the *remaining* URL and the *entire* URL are the same thing. + +The other possible `pathMatch` value is `'prefix'` which tells the router +to match the redirect route when the *remaining* URL ***begins*** with the redirect route's _prefix_ path. + +Don't do that here. +If the `pathMatch` value were `'prefix'`, _every_ URL would match `''`. + +Try setting it to `'prefix'` then click the `Go to sidekicks` button. +Remember that's a bad URL and you should see the "Page not found" page. +Instead, you're still on the "Heroes" page. +Enter a bad URL in the browser address bar. +You're instantly re-routed to `/heroes`. +_Every_ URL, good or bad, that falls through to _this_ route definition +will be a match. + +The default route should redirect to the `HeroListComponent` _only_ when the _entire_ url is `''`. +Remember to restore the redirect to `pathMatch = 'full'`. + +Learn more in Victor Savkin's +[post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes). + +A future update to this guide will cover redirects in more detail.### "Getting Started" wrap-up + +You've got a very basic, navigating app, one that can switch between two views +when the user clicks a link. + +You've learned how to + +* load the router library +* add a nav bar to the shell template with anchor tags, `routerLink` and `routerLinkActive` directives +* add a `router-outlet` to the shell template where views will be displayed +* configure the router module with `RouterModule.forRoot` +* set the router to compose "HTML 5" browser URLs +* handle invalid routes with a `wildcard` route +* navigate to the default route when the app launches with an empty path + +The rest of the starter app is mundane, with little interest from a router perspective. +Here are the details for readers inclined to build the sample through to this milestone. + +The starter app's structure looks like this: + +<aio-filetree> + + <aio-folder> + router-sample + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + crisis-list.component.ts + </aio-file> + + + <aio-file> + hero-list.component.ts + </aio-file> + + + <aio-file> + not-found.component.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +Here are the files discussed in this milestone + +<md-tab-group> + + <md-tab label="app.component.ts"> + {@example 'router/ts/src/app/app.component.1.ts'} + </md-tab> + + + <md-tab label="app.module.ts"> + {@example 'router/ts/src/app/app.module.1.ts'} + </md-tab> + + + <md-tab label="main.ts"> + {@example 'router/ts/src/main.ts'} + </md-tab> + + + <md-tab label="hero-list.component.ts"> + {@example 'router/ts/src/app/hero-list.component.ts'} + </md-tab> + + + <md-tab label="crisis-list.component.ts"> + {@example 'router/ts/src/app/crisis-list.component.ts'} + </md-tab> + + + <md-tab label="not-found.component.ts"> + {@example 'router/ts/src/app/not-found.component.ts'} + </md-tab> + + + <md-tab label="index.html"> + {@example 'router/ts/src/index.html'} + </md-tab> + + +</md-tab-group> + + +## Milestone 2: *Routing module* + +In the initial route configuration, you provided a simple setup with two routes used +to configure the application for routing. This is perfectly fine for simple routing. +As the application grows and you make use of more `Router` features, such as guards, +resolvers, and child routing, you'll naturally want to refactor the routing configuration into its own file. +We recommend moving the routing information into a special-purpose module called a *Routing Module*. + +The **Routing Module** +* separates routing concerns from other application concerns +* provides a module to replace or remove when testing the application +* provides a well-known location for routing service providers including guards and resolvers +* does **not** [declare components](../cookbook/ngmodule-faq.html#routing-module) +### Refactor routing configuration into a _routing module_ + +Create a file named `app-routing.module.ts` in the `/app` folder to contain the routing module. + +Import the `CrisisListComponent` and the `HeroListComponent` components +just like you did in the `app.module.ts`. Then move the `Router` imports +and routing configuration, including `RouterModule.forRoot`, into this routing module. + +Following convention, add a class name `AppRoutingModule` and export it +so you can import it later in `AppModule`. + +Finally, re-export the Angular `RouterModule` by adding it to the module `exports` array. +By re-exporting the `RouterModule` here and importing `AppRouterModule` in `AppModule`, +the components declared in `AppModule` will have access to router directives such as `RouterLink` and `RouterOutlet`. + +After these steps, the file should look like this. + +{@example 'router/ts/src/app/app-routing.module.1.ts'} + +Next, update the `app.module.ts` file, +first importing the new-created `AppRoutingModule`from `app-routing.module.ts`, +then replacing `RouterModule.forRoot` in the `imports` array with the `AppRoutingModule`. + +{@example 'router/ts/src/app/app.module.2.ts'} + + +Later in this guide you will create [multiple routing modules](#hero-routing-module) and discover that +you must import those routing modules [in the correct order](#routing-module-order). +The application continues to work just the same, and you can use `AppRoutingModule` as +the central place to maintain future routing configuration. + + +{@a why-routing-module} +### Do you need a _Routing Module_? + +The _Routing Module_ *replaces* the routing configuration in the root or feature module. +_Either_ configure routes in the Routing Module _or_ within the module itself but not in both. + +The Routing Module is a design choice whose value is most obvious when the configuration is complex +and includes specialized guard and resolver services. +It can seem like overkill when the actual configuration is dead simple. + +Some developers skip the Routing Module (e.g., `AppRoutingModule`) when the configuration is simple and +merge the routing configuration directly into the companion module (e.g., `AppModule`). + +We recommend that you choose one pattern or the other and follow that pattern consistently. + +Most developers should always implement a Routing Module for the sake of consistency. +It keeps the code clean when configuration becomes complex. +It makes testing the feature module easier. +Its existence calls attention to the fact that a module is routed. +It is where developers expect to find and expand routing configuration. + +## Milestone 3: Heroes feature + +You've seen how to navigate using the `RouterLink` directive, +now you'll learn how to + +* Organize the app and routes into *feature areas* using modules +* Navigate imperatively from one component to another +* Pass required and optional information in route parameters + +This example recreates the heroes feature in the "Services" episode of the +[Tour of Heroes tutorial](../tutorial/toh-pt4.html "Tour of Heroes: Services"), +and you'll be copying much of the code +from the <live-example name="toh-4" title="Tour of Heroes: Services example code"></live-example>. + +Here's how the user will experience this version of the app: + +<figure class='image-display'> + <img src='/resources/images/devguide/router/router-2-anim.gif' alt="App in action"> </img> +</figure> + +A typical application has multiple *feature areas*, +each dedicated to a particular business purpose. + +While you could continue to add files to the `src/app/` folder, +that is unrealistic and ultimately not maintainable. +Most developers prefer to put each feature area in its own folder. + +You are about to break up the app into different *feature modules*, each with its own concerns. +Then you'll import into the main module and navigate among them. +### Add Heroes functionality + +Follow these steps: + +- Create the `src/app/heroes` folder; you'll be adding files implementing *hero management* there. +- Delete the placeholder `hero-list.component.ts` that's in the `app` folder. +- Create a new `hero-list.component.ts` under `src/app/heroes`. +- Copy into it the contents of the `app.component.ts` from + the <live-example name="toh-4" title="Tour of Heroes: Services example code">"Services" tutorial</live-example>. +- Make a few minor but necessary changes: + - Delete the `selector` (routed component don't need them). + - Delete the `<h1>`. + - Relabel the `<h2>` to `<h2>HEROES</h2>`. + - Delete the `<my-hero-detail>` at the bottom of the template. + - Rename the `AppComponent` class to `HeroListComponent`. +- Copy the `hero-detail.component.ts` and the `hero.service.ts` files into the `heroes` subfolder. +- Create a (pre-routing) `heroes.module.ts` in the heroes folder that looks like this: + + +{@example 'router/ts/src/app/heroes/heroes.module.ts' region='v1'} + +When you're done, you'll have these *hero management* files: + +<aio-filetree> + + <aio-folder> + src/app/heroes + <aio-file> + hero-detail.component.ts + </aio-file> + + + <aio-file> + hero-list.component.ts + </aio-file> + + + <aio-file> + hero.service.ts + </aio-file> + + + <aio-file> + heroes.module.ts + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +### *Hero* feature routing requirements + +The heroes feature has two interacting components, the hero list and the hero detail. +The list view is self-sufficient; you navigate to it, it gets a list of heroes and displays them. + +The detail view is different. It displays a particular hero. It can't know which hero to show on its own. +That information must come from outside. + +When the user selects a hero from the list, the app should navigate to the detail view +and show that hero. +You tell the detail view which hero to display by including the selected hero's id in the route URL. + + +{@a hero-routing-module} +### *Hero* feature route configuration + +Create a new `heroes-routing.module.ts` in the `heroes` folder +using the same techniques you learned while creating the `AppRoutingModule`. + + +{@example 'router/ts/src/app/heroes/heroes-routing.module.ts'} + + +Put the Routing Module file in the same folder as its companion module file. +Here both `heroes-routing.module.ts` and `heroes.module.ts` are in the same `src/app/heroes` folder. + +We recommend giving each feature module its own route configuration file. +It may seem like overkill early when the feature routes are simple. +But routes have a tendency to grow more complex and consistency in patterns pays off over time. +Import the hero components from their new locations in the `src/app/heroes/` folder, define the two hero routes. +and export the `HeroRoutingModule` class. + +Now that you have routes for the `Heroes` module, register them with the `Router` via the +`RouterModule` _almost_ as you did in the `AppRoutingModule`. + +There is a small but critical difference. +In the `AppRoutingModule`, you used the static `RouterModule.`**`forRoot`** method to register the routes and application level service providers. +In a feature module you use static **`forChild`** method. + +Only call `RouterModule.forRoot` in the root `AppRoutingModule` +(or the `AppModule` if that's where you register top level application routes). +In any other module, you must call the `RouterModule.`**`forChild`** method to register additional routes. +### Add the routing module to the _HeroesModule_ +Add the `HeroRoutingModule` to the `HeroModule` +just as you added `AppRoutingModule` to the `AppModule`. + +Open `heroes.module.ts`. +Import the `HeroRoutingModule` token from `heroes-routing.module.ts` and +add it to the `imports` array of the `HeroesModule`. +The finished `HeroesModule` looks like this: + + +{@example 'router/ts/src/app/heroes/heroes.module.ts'} + +### Remove duplicate hero routes + +The hero routes are currently defined in _two_ places: in the `HeroesRoutingModule`, +by way of the `HeroesModule`, and in the `AppRoutingModule`. + +Routes provided by feature modules are combined together into their imported module's routes by the router. +This allows you to continue defining the feature module routes without modifying the main route configuration. + +But you don't want to define the same routes twice. +Remove the `HeroListComponent` import and the `/heroes` route from the `app-routing.module.ts`. + +**Leave the default and the wildcard routes!** +These are concerns at the top level of the application itself. + + +{@a merge-hero-routes} +### Import hero module into AppModule +The heroes feature module is ready, but the application doesn't know about the `HeroesModule` yet. +Open `app.module.ts` and revise it as follows. + +Import the `HeroesModule` and add it to the `imports` array in the `@NgModule` metadata of the `AppModule` + +Remove the `HeroListComponent` from the `AppModule`'s `declarations` because it's now provided by the `HeroesModule`. +This is important. There can be only _one_ owner for a declared component. +In this case, the `Heroes` module is the owner of the `Heroes` components and is making them available to +components in the `AppModule` via the `HeroesModule`. + +As a result, the `AppModule` no longer has specific knowledge of the hero feature, its components, or its route details. +You can evolve the hero feature with more components and different routes. +That's a key benefit of creating a separate module for each feature area. + +After these steps, the `AppModule` should look like this: + + +{@example 'router/ts/src/app/app.module.3.ts'} + + + +{@a routing-module-order} +### Module import order matters + +Look at the module `imports` array. Notice that the `AppRoutingModule` is _last_. +Most importantly, it comes _after_ the `HeroesModule`. + +{@example 'router/ts/src/app/app.module.3.ts' region='module-imports'} + +The order of route configuration matters. +The router accepts the first route that matches a navigation request path. + +When all routes were in one `AppRoutingModule`, +you put the default and [wildcard](#wildcard-route) routes last, after the `/heroes` route, +so that the router had a chance to match a URL to the `/heroes` route _before_ +hitting the wildcard route and navigating to "Page not found". + +The routes are no longer in one file. +They are distributed across two modules, `AppRoutingModule` and `HeroesRoutingModule`. + +Each routing module augments the route configuration _in the order of import_. +If you list `AppRoutingModule` first, the wildcard route will be registered +_before_ the hero routes. +The wildcard route — which matches _every_ URL — +will intercept the attempt to navigate to a hero route. + +Reverse the routing modules and see for yourself that +a click of the heroes link results in "Page not found". +Learn about inspecting the runtime router configuration +[below](#inspect-config "Inspect the router config"). +### Route definition with a parameter + +Return to the `HeroesRoutingModule` and look at the route definitions again. +The route to `HeroDetailComponent` has a twist. +Notice the `:id` token in the path. That creates a slot in the path for a **Route Parameter**. +In this case, the router will insert the `id` of a hero into that slot. + +If you tell the router to navigate to the detail component and display "Magneta", +you expect a hero id to appear in the browser URL like this: + +<code-example format="nocode"> + localhost:3000/hero/15 + +</code-example> + +If a user enters that URL into the browser address bar, the router should recognize the +pattern and go to the same "Magneta" detail view. + + +~~~ {.callout.is-helpful} + + +<header> + Route parameter: Required or optional? +</header> + +Embedding the route parameter token, `:id`, +in the route definition path is a good choice for this scenario +because the `id` is *required* by the `HeroDetailComponent` and because +the value `15` in the path clearly distinguishes the route to "Magneta" from +a route for some other hero. + + +~~~ + + + +{@a navigate} +### Navigate to hero detail imperatively + +Users *will not* navigate to the detail component by clicking a link +so you won't add a new `RouterLink` anchor tag to the shell. + +Instead, when the user *clicks* a hero in the list, you'll ask the router +to navigate to the hero detail view for the selected hero. + +Start in the `HeroListComponent`. +Revise its constructor so that it acquires the `Router` and the `HeroService` by dependency injection: +Make the following few changes to the component's template: +The template defines an `*ngFor` repeater such as [you've seen before](displaying-data.html#ngFor). +There's a `(click)` [event binding](template-syntax.html#event-binding) to the component's +`onSelect` method which you implement as follows: +The component's `onSelect` calls the router's **`navigate`** method with a _link parameters array_. +You can use this same syntax in a `RouterLink` if you decide later to navigate in HTML template rather than in component code. + + +{@a route-parameters} +### Setting the route parameters in the list view + +After navigating to the `HeroDetailComponent`, you expect to see the details of the selected hero. +You'll need *two* pieces of information: the routing path to the component and the hero's `id`. + +Accordingly, the _link parameters array_ has *two* items: the routing _path_ and a _route parameter_ that specifies the +`id` of the selected hero. +The router composes the destination URL from this array: +`localhost:3000/hero/15`. + + +{@a get-route-parameter} +### Getting the route parameter in the details view + +How does the target `HeroDetailComponent` learn about that `id`? +Don't analyze the URL. Let the router do it. + +The router extracts the route parameter (`id:15`) from the URL and supplies it to +the `HeroDetailComponent` via the `ActivatedRoute` service. + + +{@a activated-route} +### ActivatedRoute: the one-stop-shop for route information + +The route path and parameters are available through an injected router service called the +[ActivatedRoute](../api/router/index/ActivatedRoute-interface.html). +It has a great deal of useful information including: + +**`url`**: An `Observable` of the route path(s), represented as an array of strings for each part of the route path. + +**`data`**: An `Observable` that contains the `data` object provided for the route. Also contains any resolved values from the [resolve guard](#resolve-guard). + +**`params`**: An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. + +**`queryParams`**: An `Observable` that contains the [query parameters](#query-parameters) available to all routes. + +**`fragment`**: An `Observable` of the URL [fragment](#fragment) available to all routes. + +**`outlet`**: The name of the `RouterOutlet` used to render the route. For an unnamed outlet, the outlet name is _primary_. + +**`routeConfig`**: The route configuration used for the route that contains the origin path. + +**`parent`**: an `ActivatedRoute` that contains the information from the parent route when using [child routes](#child-routing-component). + +**`firstChild`**: contains the first `ActivatedRoute` in the list of child routes. + +**`children`**: contains all the [child routes](#child-routing-component) activated under the current route. +Import the `Router`, `ActivatedRoute`, and `Params` tokens from the router package. +Import the `switchMap` operator because you need it later to process the `Observable` route parameters. + + +{@a hero-detail-ctor} +As usual, you write a constructor that asks Angular to inject services +that the component requires and reference them as private variables. +Later, in the `ngOnInit` method, you use the `ActivatedRoute` service to retrieve the parameters for the route, +pull the hero `id` from the parameters and retrieve the hero to display. + +Put this data access logic in the `ngOnInit` method rather than inside the constructor to improve the component's testability. +Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent` +so the hero will be retrieved in time to use it. + +Learn more about the `ngOnInit` method and other component lifecycle hooks in the [Lifecycle Hooks](lifecycle-hooks.html) guide. +Since the parameters are provided as an `Observable`, you use the _switchMap_ operator to +provide them for the `id` parameter by name and tell the `HeroService` to fetch the hero with that `id`. + +The `switchMap` operator allows you to perform an action with the current value of the `Observable`, +and map it to a new `Observable`. As with many `rxjs` operators, `switchMap` handles +an `Observable` as well as a `Promise` to retrieve the value they emit. + +The `switchMap` operator will also cancel any in-flight requests if the user re-navigates to the route +while still retrieving a hero. + +Use the `subscribe` method to detect `id` changes and to (re)set the retrieved `Hero`. + +<h4 id='reuse'> + Observable <i>params</i> and component re-use +</h4> + +In this example, you retrieve the route params from an `Observable`. +That implies that the route params can change during the lifetime of this component. + +They might. By default, the router re-uses a component instance when it re-navigates to the same component type +without visiting a different component first. The route parameters could change each time. + +Suppose a parent component navigation bar had "forward" and "back" buttons +that scrolled through the list of heroes. +Each click navigated imperatively to the `HeroDetailComponent` with the next or previous `id`. + +You don't want the router to remove the current `HeroDetailComponent` instance from the DOM only to re-create it for the next `id`. +That could be visibly jarring. +Better to simply re-use the same component instance and update the parameter. + +Unfortunately, `ngOnInit` is only called once per component instantiation. +You need a way to detect when the route parameters change from _within the same instance_. +The observable `params` property handles that beautifully. + +When subscribing to an observable in a component, you almost always arrange to unsubscribe when the component is destroyed. + +There are a few exceptional observables where this is not necessary. +The `ActivatedRoute` observables are among the exceptions. + +The `ActivatedRoute` and its observables are insulated from the `Router` itself. +The `Router` destroys a routed component when it is no longer needed and the injected `ActivatedRoute` dies with it. + +Feel free to unsubscribe anyway. It is harmless and never a bad practice. + + +{@a snapshot} +#### _Snapshot_: the _no-observable_ alternative +_This_ application won't re-use the `HeroDetailComponent`. +The user always returns to the hero list to select another hero to view. +There's no way to navigate from one hero detail to another hero detail +without visiting the list component in between. +Therefore, the router creates a new `HeroDetailComponent` instance every time. + +When you know for certain that a `HeroDetailComponent` instance will *never, never, ever* +be re-used, you can simplify the code with the *snapshot*. + +The `route.snapshot` provides the initial value of the route parameters. +You can access the parameters directly without subscribing or adding observable operators. +It's much simpler to write and read: + +**Remember:** you only get the _initial_ value of the parameters with this technique. +Stick with the observable `params` approach if there's even a chance that the router +could re-use the component. +This sample stays with the observable `params` strategy just in case. + + +{@a nav-to-list} +### Navigating back to the list component + +The `HeroDetailComponent` has a "Back" button wired to its `gotoHeroes` method that navigates imperatively +back to the `HeroListComponent`. + +The router `navigate` method takes the same one-item _link parameters array_ +that you can bind to a `[routerLink]` directive. +It holds the _path to the `HeroListComponent`_: + +### Route Parameters: Required or optional? + +Use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL +as you do when navigating to the `HeroDetailComponent` in order to view the hero with *id* 15: + +<code-example format="nocode"> + localhost:3000/hero/15 + +</code-example> + +You can also add *optional* information to a route request. +For example, when returning to the heroes list from the hero detail view, +it would be nice if the viewed hero was preselected in the list. + +<figure class='image-display'> + <img src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero"> </img> +</figure> + +You'll implement this feature in a moment by including the viewed hero's `id` +in the URL as an optional parameter when returning from the `HeroDetailComponent`. + +Optional information takes other forms. Search criteria are often loosely structured, e.g., `name='wind*'`. +Multiple values are common — `after='12/31/2015' & before='1/1/2017'` — in no particular order — + `before='1/1/2017' & after='12/31/2015'` — in a variety of formats — `during='currentYear'` . + +These kinds of parameters don't fit easily in a URL *path*. Even if you could define a suitable URL token scheme, +doing so greatly complicates the pattern matching required to translate an incoming URL to a named route. + +Optional parameters are the ideal vehicle for conveying arbitrarily complex information during navigation. +Optional parameters aren't involved in pattern matching and afford flexibility of expression. + +The router supports navigation with optional parameters as well as required route parameters. +Define _optional_ parameters in a separate object _after_ you define the required route parameters. + +In general, prefer a *required route parameter* when +the value is mandatory (for example, if necessary to distinguish one route path from another); +prefer an *optional parameter* when the value is optional, complex, and/or multi-variate. +### Heroes list: optionally selecting a hero + +When navigating to the `HeroDetailComponent` you specified the _required_ `id` of the hero-to-edit in the +*route parameter* and made it the second item of the [_link parameters array_](#link-parameters-array). +The router embedded the `id` value in the navigation URL because you had defined it +as a route parameter with an `:id` placeholder token in the route `path`: +When the user clicks the back button, the `HeroDetailComponent` constructs another _link parameters array_ +which it uses to navigate back to the `HeroListComponent`. +This array lacks a route parameter because you had no reason to send information to the `HeroListComponent`. + +Now you have a reason. You'd like to send the id of the current hero with the navigation request so that the +`HeroListComponent` can highlight that hero in its list. +This is a _nice-to-have_ feature; the list will display perfectly well without it. + +Send the `id` with an object that contains an _optional_ `id` parameter. +For demonstration purposes, there's an extra junk parameter (`foo`) in the object that the `HeroListComponent` should ignore. +Here's the revised navigation statement: +The application still works. Clicking "back" returns to the hero list view. + +Look at the browser address bar. +It should look something like this, depending on where you run it: + +<code-example language="bash"> + localhost:3000/heroes;id=15;foo=foo + +</code-example> + +The `id` value appears in the URL as (`;id=15;foo=foo`), not in the URL path. +The path for the "Heroes" route doesn't have an `:id` token. + +The optional route parameters are not separated by "?" and "&" as they would be in the URL query string. +They are **separated by semicolons ";"** +This is *matrix URL* notation — something you may not have seen before. + +*Matrix URL* notation is an idea first floated +in a [1996 proposal](http://www.w3.org/DesignIssues/MatrixURIs.html) by the founder of the web, Tim Berners-Lee. + +Although matrix notation never made it into the HTML standard, it is legal and +it became popular among browser routing systems as a way to isolate parameters +belonging to parent and child routes. The Router is such a system and provides +support for the matrix notation across browsers. + +The syntax may seem strange to you but users are unlikely to notice or care +as long as the URL can be emailed and pasted into a browser address bar +as this one can. +### Route parameters in the *ActivatedRoute* service + +The list of heroes is unchanged. No hero row is highlighted. + +The <live-example></live-example> *does* highlight the selected +row because it demonstrates the final state of the application which includes the steps you're *about* to cover. +At the moment you're describing the state of affairs *prior* to those steps.The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them. +You can change that. + +Previously, when navigating from the `HeroListComponent` to the `HeroDetailComponent`, +you subscribed to the route params `Observable` and made it available to the `HeroDetailComponent` +in the `ActivatedRoute` service. +You injected that service in the constructor of the `HeroDetailComponent`. + +This time you'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`. + +First you extend the router import statement to include the `ActivatedRoute` service symbol; +Import the `switchMap` operator to perform an operation on the `Observable` of route parameters. +Then you inject the `ActivatedRoute` in the `HeroListComponent` constructor. +The ActivatedRoute.params property is an Observable of route parameters. The params emits new id values +when the user navigates to the component. In ngOnInit you subscribe to those values, set the selectedId, +and get the heroes. + +All route/query parameters are strings. +The (+) in front of the `params['id']` expression is a JavaScript trick to convert the string to an integer.Add an `isSelected` method that returns true when a hero's id matches the selected id. +Finally, you update the template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method. +The binding adds the `selected` CSS class when the method returns `true` and removes it when `false`. +Look for it within the repeated `<li>` tag as shown here: +When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected: +<figure class='image-display'> + <img src='/resources/images/devguide/router/selected-hero.png' alt="Selected List"> </img> +</figure> + +The optional `foo` route parameter is harmless and continues to be ignored. + +<h3 id='route-animation'> + Adding animations to the routed component +</h3> + +The heroes feature module is almost complete, but what is a feature without some smooth transitions? + +In this section you'll add some [animations](../guide/animations.html) to the *Hero Detail* component. + +Create an `animations.ts` file in the root `src/app/` folder. The contents look like this:This file does the following: + +* Imports the animation symbols that build the animation triggers, control state, and manage transitions between states. + +* Exports a constant named `slideInDownAnimation` set to an animation trigger named *routeAnimation*; +animated components will refer to this name. + +* Specifies the _wildcard state_ that matches any animation state that the route component is in. + +* Defines two *transitions*, one to ease the component in from the left of the screen as it enters the application view (`:enter`), +the other to animate the component down as it leaves the application view (`:leave`). + +You could create more triggers with different transitions for other route components. This trigger is sufficient for the current milestone. +Back in the `HeroDetailComponent`, import the `slideInDownAnimation` from `'./animations.ts`. +Add the `HostBinding` decorator to the imports from `@angular/core`; you'll need it in a moment. + +Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`. + +Then add three `@HostBinding` properties to the class to set the animation and styles for the route component's element.The `'@routeAnimation'` passed to the first `@HostBinding` matches the name of the `slideInDownAnimation` _trigger_. +Set the `routeAnimation` property to `true` because you only care about the `:enter` and `:leave` states. + +The other two `@HostBinding` properties style the display and position of the component. + +The `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away. + +Applying route animations to individual components is something you'd rather not do throughout the entire application. +It would be better to animate routes based on _route paths_, a topic to cover in a future update to this guide. +### Milestone 3 wrap-up + +You've learned how to + +* organize the app into *feature areas* +* navigate imperatively from one component to another +* pass information along in route parameters and subscribe to them in the component +* import the feature area NgModule into the `AppModule` +* apply animations to the route component + +After these changes, the folder structure looks like this: + +<aio-filetree> + + <aio-folder> + router-sample + <aio-folder> + src + <aio-folder> + app + <aio-folder> + heroes + <aio-file> + hero-detail.component.ts + </aio-file> + + + <aio-file> + hero-list.component.ts + </aio-file> + + + <aio-file> + hero.service.ts + </aio-file> + + + <aio-file> + heroes.module.ts + </aio-file> + + + <aio-file> + heroes-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + app-routing.module.ts + </aio-file> + + + <aio-file> + crisis-list.component.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + + +<md-tab-group> + + <md-tab label="app.component.ts"> + {@example 'router/ts/src/app/app.component.1.ts'} + </md-tab> + + + <md-tab label="app.module.ts"> + {@example 'router/ts/src/app/app.module.3.ts'} + </md-tab> + + + <md-tab label="app-routing.module.ts"> + {@example 'router/ts/src/app/app-routing.module.2.ts'} + </md-tab> + + + <md-tab label="hero-list.component.ts"> + {@example 'router/ts/src/app/heroes/hero-list.component.ts'} + </md-tab> + + + <md-tab label="hero-detail.component.ts"> + {@example 'router/ts/src/app/heroes/hero-detail.component.ts'} + </md-tab> + + + <md-tab label="hero.service.ts"> + {@example 'router/ts/src/app/heroes/hero.service.ts'} + </md-tab> + + + <md-tab label="heroes.module.ts"> + {@example 'router/ts/src/app/heroes/heroes.module.ts'} + </md-tab> + + + <md-tab label="heroes-routing.module.ts"> + {@example 'router/ts/src/app/heroes/heroes-routing.module.ts'} + </md-tab> + + +</md-tab-group> + + + +{@a milestone-4} + +## Milestone 4: Crisis center feature + +It's time to add real features to the app's current placeholder crisis center. + +Begin by imitating the heroes feature: + +- Delete the placeholder crisis center file. +- Create !{_an} `!{_appDir}/crisis-center` folder. +- Copy the files from `!{_appDir}/heroes` into the new crisis center folder, but +- Change every mention of "hero" to "crisis", and "heroes" to "crises". + +You'll turn the `CrisisService` into a purveyor of mock crises instead of mock heroes: +The resulting crisis center is a foundation for introducing a new concept — **child routing**. +You can leave *Heroes* in its current state as a contrast with the *Crisis Center* +and decide later if the differences are worthwhile. + + +~~~ {.alert.is-helpful} + +In keeping with the +<a href="https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" target="_blank" title="Separation of Concerns">*Separation of Concerns* principle</a>, +changes to the *Crisis Center* won't affect the `!{_AppModuleVsAppComp}` or +any other feature's component. + + +~~~ + +### A Crisis center with child routes + +You'll organize the crisis center to conform to the following recommended pattern for Angular applications: + +* Each feature area resides in its own folder +* Each feature has its own Angular feature module. +* Each area has its own area root component. +* Each area root component has its own router outlet and child routes. +* Feature area routes rarely (if ever) cross with routes of other features. + +If your app had many feature areas, the app component trees might look like this: + +<figure class='image-display'> + <img src='/resources/images/devguide/router/component-tree.png' alt="Component Tree"> </img> +</figure> + +### Child routing component + +Add the following `crisis-center.component.ts` to the `crisis-center` folder: +Much like the `AppComponent`, the `CrisisCenterComponent` is the + +- *Root* of the crisis center area, +just as `AppComponent` is the root of the entire application +- *Shell* for the crisis management feature area, +just as the `AppComponent` is a shell to manage the high-level workflow + +Like most shells, the `CrisisCenterComponent` class is very simple, simpler even than `AppComponent`: +it has no business logic, and its template has no links, just a title and +`<router-outlet>` for the crisis center child views. + +Unlike `AppComponent`, and most other components, it _lacks a selector_. +It doesn't _need_ one since you don't *embed* this component in a parent template, +instead you use the router to *navigate* to it. +### Child route configuration + +The `CrisisCenterComponent` is a *routing component* like the `AppComponent`. +It has its own `RouterOutlet` and its own child routes. + +Add the following `crisis-center-home.component.ts` to the `crisis-center` folder. +Create a `crisis-center-routing.module.ts` file as you did the `heroes-routing.module.ts` file. +This time, you define **child routes** *within* the parent `crisis-center` route. +Notice that the parent `crisis-center` route has a `children` property +with a single route containing the `CrisisListComponent`. The `CrisisListComponent` route +also has a `children` array with two routes. + +These two routes navigate to the crisis center child components, +`CrisisCenterHomeComponent` and `CrisisDetailComponent`, respectively. + +There are *important differences* in the way the router treats these _child routes_. + +The router displays the components of these routes in the `RouterOutlet` +of the `CrisisCenterComponent`, not in the `RouterOutlet` of the `AppComponent` shell. + +The `CrisisListComponent` contains the crisis list and a `RouterOutlet` to +display the `Crisis Center Home` and `Crisis Detail` route components. + +The `Crisis Detail` route is a child of the `Crisis List`. Since the router [reuses components](#reuse) +by default, the `Crisis Detail` component will be re-used as you select different crises. +In contrast, back in the `Hero Detail` route, the component was recreated each time you selected a different hero. + +At the top level, paths that begin with `/` refer to the root of the application. +But child routes *extend* the path of the parent route. +With each step down the route tree, +you add a slash followed by the route path, unless the path is _empty_. + +Apply that logic to navigation within the crisis center for which the parent path is `/crisis-center`. + +* To navigate to the `CrisisCenterHomeComponent`, the full URL is `/crisis-center` (`/crisis-center` + `''` + `''`). + +* To navigate to the `CrisisDetailComponent` for a crisis with `id=2`, the full URL is +`/crisis-center/2` (`/crisis-center` + `''` + `'/2'`). + +The absolute URL for the latter example, including the `localhost` origin, is +<code-example> + localhost:3000/crisis-center/2 + +</code-example> + +Here's the complete `crisis-center-routing.module.ts` file with its imports. + + +{@a import-crisis-module} +### Import crisis center module into the *AppModule* routes + +As with the `HeroesModule`, you must add the `CrisisCenterModule` to the `imports` array of the `AppModule` +_before_ the `AppRoutingModule`: +Remove the initial crisis center route from the `app-routing.module.ts`. +The feature routes are now provided by the `HeroesModule` and the `CrisisCenter` modules. + +The `app-routing.module.ts` file retains the top-level application routes such as the default and wildcard routes. + + + +{@a relative-navigation} +### Relative navigation + +While building out the crisis center feature, you navigated to the +crisis detail route using an **absolute path** that begins with a _slash_. + +The router matches such _absolute_ paths to routes starting from the top of the route configuration. + +You could continue to use absolute paths like this to navigate inside the *Crisis Center* +feature, but that pins the links to the parent routing structure. +If you changed the parent `/crisis-center` path, you would have to change the link parameters array. + +You can free the links from this dependency by defining paths that are **relative** to the current URL segment. +Navigation _within_ the feature area remains intact even if you change the parent route path to the feature. + +Here's an example + +The router supports directory-like syntax in a _link parameters list_ to help guide route name lookup: + +`./` or `no leading slash` is relative to the current level. + +`../` to go up one level in the route path. + +You can combine relative navigation syntax with an ancestor path. +If you must navigate to a sibling route, you could use the `../<sibling>` convention to go up +one level, then over and down the sibling route path. +To navigate a relative path with the `Router.navigate` method, you must supply the `ActivatedRoute` +to give the router knowledge of where you are in the current route tree. + +After the _link parameters array_, add an object with a `relativeTo` property set to the `ActivatedRoute`. +The router then calculates the target URL based on the active route's location. + +**Always** specify the complete _absolute_ path when calling router's `navigateByUrl` method. +### Navigate to crisis detail with a relative URL + +Update the *Crisis List* `onSelect` method to use relative navigation so you don't have +to start from the top of the route configuration. + +You've already injected the `ActivatedRoute` that you need to compose the relative navigation path.When you visit the *Crisis Center*, the ancestor path is `/crisis-center`, +so you only need to add the `id` of the *Crisis Center* to the existing path. +If you were using a `RouterLink` to navigate instead of the `Router` service, you'd use the _same_ +link parameters array, but you wouldn't provide the object with the `relativeTo` property. +The `ActivatedRoute` is implicit in a `RouterLink` directive. +Update the `gotoCrises` method of the `CrisisDetailComponent` to navigate back to the *Crisis Center* list using relative path navigation. +Notice that the path goes up a level (`../`) syntax. +If the current crisis `id` is `3`, the resulting path back to the crisis list is `/crisis-center/;id=3;foo=foo`. + + +{@a named-outlets} + +### Displaying multiple routes in named outlets + +You decide to give users a way to contact the crisis center. +When a user clicks a "Contact" button, you want to display a message in a popup view. + +The popup should stay open, even when switching between pages in the application, until the user closes it +by sending the message or canceling. +Clearly you can't put the popup in the same outlet as the other pages. + +Until now, you've defined a single outlet and you've nested child routes +under that outlet to group routes together. +The router only supports one primary _unnamed_ outlet per template, + +A template can also have any number of _named_ outlets. +Each named outlet has its own set of routes with their own components. +Multiple outlets can be displaying different content, determined by different routes, all at the same time. + +Add an outlet named "popup" in the `AppComponent`, directly below the unnamed outlet. +That's where a popup will go, once you learn how to route a popup component to it. + + +{@a secondary-routes} +#### Secondary routes + +Named outlets are the targets of _secondary routes_. + +Secondary routes look like primary routes and you configure them the same way. +They differ in a few key respects. + +* They are independent of each other +* They work in combination with other routes. +* They are displayed in named outlets. + +Create a new component named `ComposeMessageComponent` in `src/app/compose-message.component.ts`. +It displays a simple form with a header, an input box for the message, +and two buttons, "Send" and "Cancel". + +<figure class='image-display'> + <img src='/resources/images/devguide/router/contact-popup.png' alt="Contact popup" width="250"> </img> +</figure> + +Here's the component and its template: + +<md-tab-group> + + <md-tab label="src/app/compose-message.component.ts"> + {@example 'router/ts/src/app/compose-message.component.ts'} + </md-tab> + + + <md-tab label="src/app/compose-message.component.html"> + {@example 'router/ts/src/app/compose-message.component.html'} + </md-tab> + + +</md-tab-group> + +It looks about the same as any other component you've seen in this guide. +There are two noteworthy differences + +Note that the `send` method simulates latency by waiting a second before "sending" the message and closing the popup. + +The `closePopup` method closes the popup view by navigating to the "popup" outlet with a `null`. +That's a peculiarity covered [below](#clear-secondary-routes). + +As with other application components, you add the `ComposeMessageComponent` to the `declarations` of an `NgModule`. +Do so in the `AppModule`. + +#### Add a secondary route + +Open the `AppRoutingModule` and add a new `compose` route to the `appRoutes`.The `path` and `component` properties should be familiar. +There's a new property `outlet` set to `'popup'`. +This route now targets the "popup" outlet and the `ComposeMessageComponent` will display there. + +The user needs a way to open the popup. +Open the `AppComponent` and add a "Contact" link.Although the `compose` route is pinned to the "popup" outlet, that's not sufficient for wiring the route to a `RouterLink` directive. +You have to specify the named outlet in a _link parameters array_ and bind it to the `RouterLink` with a property binding. + +The _link parameters array_ contains an object with a single `outlets` property whose value +is another object keyed by one (or more) outlet names. +In this case there is only the "popup" outlet property and its value is another _link parameters array_ that specifies the `compose` route. + +You are in effect saying, _when the user clicks this link, display the component associated with the `compose` route in the `popup` outlet_. + +This `outlets` object within an outer object was completely unnecessary +when there was only one route and one _unnamed_ outlet to think about. + +The router assumed that your route specification targeted the _unnamed_ primary outlet +and created these objects for you. + +Routing to a named outlet has revealed a previously hidden router truth: +you can target multiple outlets with multiple routes in the same `RouterLink` directive. + +You're not actually doing that here. +But to target a named outlet, you must use the richer, more verbose syntax. + +<h3 id='secondary-route-navigation'> + <i>Secondary Route Navigation</i>: merging routes during navigation +</h3> + +Navigate to the _Crisis Center_ and click "Contact". +you should see something like the following URL in the browser address bar. + +<code-example> + http://.../crisis-center(popup:compose) + +</code-example> + +The interesting part of the URL follows the `...`: +* The `crisis-center` is the primary navigation. +* Parentheses surround the secondary route. +* The secondary route consist of an outlet name (`popup`), then a `colon` separator, followed with the secondary route path (`compose`) + +Click the _Heroes_ link and look at the URL again. + +<code-example> + http://.../heroes(popup:compose) +</code-example> + +The primary navigation part has changed; the secondary route is the same. + +The router is keeping track of two separate branches in a navigation tree and generating a representation of that tree in the URL. + +You can add many more outlets and routes, at the top level and in nested levels, creating a navigation tree with many branches. +The router will generate the URL to go with it. + +You can tell the router to navigate an entire tree at once by filling out the `outlets` object mentioned above. +Then pass that object inside a _link parameters array_ to the `router.navigate` method. + +Experiment with these possibilities at your leisure. + + + +{@a clear-secondary-routes} +#### Clearing secondary routes +As you've learned, a component in an outlet persists until you navigate away to a new component. +Secondary outlets are no different in this regard. + +Each secondary outlet has its own navigation, independent of the navigation driving the primary outlet. +Changing a current route that displays in the primary outlet has no effect on the "popup" outlet. +That's why the "popup" stays visible as you navigate among the crises and heroes. + +Clicking the "send" or "cancel" buttons _does_ clear the popup view. +To see how, look at the `ComposeMessageComponent.closePopup` method again: +## Milestone 5: Route guards + +At the moment, *any* user can navigate *anywhere* in the application *anytime*. +That's not always the right thing to do. + +* Perhaps the user is not authorized to navigate to the target component. +* Maybe the user must login (*authenticate*) first. +* Maybe you should fetch some data before you display the target component. +* You might want to save pending changes before leaving a component. +* You might ask the user if it's OK to discard pending changes rather than save them. + +You can add _guards_ to the route configuration to handle these scenarios. + +A guard's return value controls the router's behavior: + +* if it returns `true`, the navigation process continues +* if it returns `false`, the navigation process stops and the user stays put + +The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation. +The guard *might* return its boolean answer synchronously. +But in many cases, the guard can't produce an answer synchronously. +The guard could ask the user a question, save changes to the server, or fetch fresh data. +These are all asynchronous operations. + +Accordingly, a routing guard can return an `Observable<boolean>` or a `Promise<boolean>` and the +router will wait for the observable to resolve to `true` or `false`. + +The router supports multiple kinds of guards: + +1. [CanActivate](../api/router/index/CanActivate-interface.html) to mediate navigation *to* a route. + +2. [CanActivateChild](../api/router/index/CanActivateChild-interface.html) to mediate navigation *to* a child route. + +3. [CanDeactivate](../api/router/index/CanDeactivate-interface.html) to mediate navigation *away* from the current route. + +4. [Resolve](../api/router/index/Resolve-interface.html) to perform route data retrieval *before* route activation. + +5. [CanLoad](../api/router/index/CanLoad-interface.html) to mediate navigation *to* a feature module loaded _asynchronously_. +You can have multiple guards at every level of a routing hierarchy. +The router checks the `CanDeactivate` and `CanActivateChild` guards first, from deepest child route to the top. +Then it checks the `CanActivate` guards from the top down to the deepest child route. If the feature module +is loaded asynchronously, the `CanLoad` guard is checked before the module is loaded. +If _any_ guard returns false, pending guards that have not completed will be canceled, +and the entire navigation is canceled. + +You'll see several examples over the next few sections. + + +{@a can-activate-guard} +### *CanActivate*: requiring authentication + +Applications often restrict access to a feature area based on who the user is. +You could permit access only to authenticated users or to users with a specific role. +You might block or limit access until the user's account is activated. + +The `CanActivate` guard is the tool to manage these navigation business rules. + +#### Add an admin feature module + +In this next section, you'll extend the crisis center with some new *administrative* features. +Those features aren't defined yet. +But you can start by adding a new feature module named `AdminModule`. + +Create an `admin` folder with a feature module file, a routing configuration file, and supporting components. + +The admin feature file structure looks like this: + +<aio-filetree> + + <aio-folder> + src/app/admin + <aio-file> + admin-dashboard.component.ts + </aio-file> + + + <aio-file> + admin.component.ts + </aio-file> + + + <aio-file> + admin.module.ts + </aio-file> + + + <aio-file> + admin-routing.module.ts + </aio-file> + + + <aio-file> + manage-crises.component.ts + </aio-file> + + + <aio-file> + manage-heroes.component.ts + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +The admin feature module contains the `AdminComponent` used for routing within the +feature module, a dashboard route and two unfinished components to manage crises and heroes. + +<md-tab-group> + + <md-tab label="src/app/admin/admin-dashboard.component.ts"> + {@example 'router/ts/src/app/admin/admin-dashboard.component.1.ts'} + </md-tab> + + + <md-tab label="src/app/admin/admin.component.ts"> + {@example 'router/ts/src/app/admin/admin.component.ts'} + </md-tab> + + + <md-tab label="src/app/admin/admin.module.ts"> + {@example 'router/ts/src/app/admin/admin.module.ts'} + </md-tab> + + + <md-tab label="src/app/admin/manage-crises.component.ts"> + {@example 'router/ts/src/app/admin/manage-crises.component.ts'} + </md-tab> + + + <md-tab label="src/app/admin/manage-heroes.component.ts"> + {@example 'router/ts/src/app/admin/manage-heroes.component.ts'} + </md-tab> + + +</md-tab-group> + + +Since the admin dashboard `RouterLink` is an empty path route in the `AdminComponent`, it +is considered a match to any route within the admin feature area. +You only want the `Dashboard` link to be active when the user visits that route. +Add an additional binding to the `Dashboard` routerLink, +`[routerLinkActiveOptions]="{ exact: true }"` which marks the `./` link as active when +the user navigates to the `/admin` URL and not when navigating to any of the child routes. +The initial admin routing configuration: + +<h3 id='component-less-route'> + <i>Component-Less Route</i>: grouping routes without a component +</h3> + +Looking at the child route under the `AdminComponent`,there is a `path` and a `children` +property but it's not using a `component`. +You haven't made a mistake in the configuration. +You've defined a _component-less_ route. + +The goal is to group the `Crisis Center` management routes under the `admin` path. +You don't need a component to do it. +A _component-less_ route makes it easier to [guard child routes](#can-activate-child-guard). +Next, import the `AdminModule` into the `app.module.ts` and add it to the `imports` array +to register the admin routes. +Add an "Admin" link to the `AppComponent` shell so that users can get to this feature. +#### Guard the admin feature + +Currently every route within the *Crisis Center* is open to everyone. +The new *admin* feature should be accessible only to authenticated users. + +You could hide the link until the user logs in. But that's tricky and difficult to maintain. + +Instead you'll write a `CanActivate` guard to redirect anonymous users to the login page when they try to enter the admin area. + +This is a general purpose guard — you can imagine other features that require authenticated users — +so you create an `auth-guard.service.ts` in the application root folder. + +At the moment you're interested in seeing how guards work so the first version does nothing useful. +It simply logs to console and `returns` true immediately, allowing navigation to proceed: +Next you open `admin-routing.module.ts `, import the `AuthGuard` class, and +update the admin route with a `CanActivate` guard property that references it: +The admin feature is now protected by the guard, albeit protected poorly. + +#### Teach *AuthGuard* to authenticate + +Make the `AuthGuard` at least pretend to authenticate. + +The `AuthGuard` should call an application service that can login a user and retain information about the current user. +Here's a demo `AuthService`: +Although it doesn't actually log in, it has what you need for this discussion. +It has an `isLoggedIn` flag to tell you whether the user is authenticated. +Its `login` method simulates an API call to an external service by returning an observable that resolves successfully after a short pause. +The `redirectUrl` property will store the attempted URL so you can navigate to it after authenticating. + +Revise the `AuthGuard` to call it. +Notice that you *inject* the `AuthService` and the `Router` in the constructor. +You haven't provided the `AuthService` yet but it's good to know that you can inject helpful services into routing guards. + +This guard returns a synchronous boolean result. +If the user is logged in, it returns true and the navigation continues. + +The `ActivatedRouteSnapshot` contains the _future_ route that will be activated and the `RouterStateSnapshot` +contains the _future_ `RouterState` of the application, should you pass through the guard check. + +If the user is not logged in, you store the attempted URL the user came from using the `RouterStateSnapshot.url` and +tell the router to navigate to a login page — a page you haven't created yet. +This secondary navigation automatically cancels the current navigation; you return `false` just to be clear about that. + +#### Add the *LoginComponent* + +You need a `LoginComponent` for the user to log in to the app. After logging in, you'll redirect +to the stored URL if available, or use the default URL. +There is nothing new about this component or the way you wire it into the router configuration. + +Register a `/login` route in the `login-routing.module.ts` and add the necessary providers to the `providers` +array. In the `app.module.ts`, import the `LoginComponent` and add it to the `AppModule` `declarations`. +Import and add the `LoginRoutingModule` to the `AppModule` imports as well. + +<md-tab-group> + + <md-tab label="src/app/app.module.ts"> + {@example 'router/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="src/app/login.component.ts"> + {@example 'router/ts/src/app/login.component.1.ts'} + </md-tab> + + + <md-tab label="src/app/login-routing.module.ts"> + {@example 'router/ts/src/app/login-routing.module.ts'} + </md-tab> + + +</md-tab-group> + + +Guards and the service providers they require _must_ be provided at the module-level. This allows +the Router access to retrieve these services from the `Injector` during the navigation process. +The same rule applies for feature modules loaded [asynchronously](#asynchronous-routing). + +<h3 id='can-activate-child-guard'> + <i>CanActivateChild</i>: guarding child routes +</h3> + +You can also protect child routes with the `CanActivateChild` guard. +The `CanActivateChild` guard is similar to the `CanActivate` guard. +The key difference is that it runs _before_ any child route is activated. + +You protected the admin feature module from unauthorized access. +You should also protect child routes _within_ the feature module. + +Extend the `AuthGuard` to protect when navigating between the `admin` routes. +Open the `auth-guard.service.ts` and add the `CanActivateChild` interface to the imported tokens from the router package. + +Next, implement the `canActivateChild` method which takes the same arguments as the `canActivate` method: +an `ActivatedRouteSnapshot` and `RouterStateSnapshot`. +The `canActivateChild` can return an `Observable<boolean>` or `Promise<boolean>` for async checks and a `boolean` for sync checks. +This one returns a `boolean` +Add the same `AuthGuard` to the `component-less` admin route to protect all other child routes at one time +instead of adding the `AuthGuard` to each route individually. + +<h3 id='can-deactivate-guard'> + <i>CanDeactivate</i>: handling unsaved changes +</h3> + +Back in the "Heroes" workflow, the app accepts every change to a hero immediately without hesitation or validation. + +In the real world, you might have to accumulate the users changes. +You might have to validate across fields. +You might have to validate on the server. +You might have to hold changes in a pending state until the user confirms them *as a group* or +cancels and reverts all changes. + +What do you do about unapproved, unsaved changes when the user navigates away? +You can't just leave and risk losing the user's changes; that would be a terrible experience. + +You'd prefer to pause and let the user decide what to do. +If the user cancels, you'll stay put and allow more changes. +If the user approves, the app can save. + +You still might delay navigation until the save succeeds. +If you let the user move to the next screen immediately and +the save failed (perhaps the data are ruled invalid), you would have lost the context of the error. + +You can't block while waiting for the server — that's not possible in a browser. +You need to stop the navigation while you wait, asynchronously, for the server +to return with its answer. + +You need the `CanDeactivate` guard. + +### Cancel and save + +The sample application doesn't talk to a server. +Fortunately, you have another way to demonstrate an asynchronous router hook. + +Users update crisis information in the `CrisisDetailComponent`. +Unlike the `HeroDetailComponent`, the user changes do not update the crisis entity immediately. +Update the entity when the user presses the *Save* button. +Discard the changes when the user presses the *Cancel* button. + +Both buttons navigate back to the crisis list after save or cancel. +What if the user tries to navigate away without saving or canceling? +The user could push the browser back button or click the heroes link. +Both actions trigger a navigation. +Should the app save or cancel automatically? + +You'll do neither. Instead you'll ask the user to make that choice explicitly +in a confirmation dialog box that *waits asynchronously for the user's +answer*. +You could wait for the user's answer with synchronous, blocking code. +The app will be more responsive ... and can do other work ... +by waiting for the user's answer asynchronously. Waiting for the user asynchronously +is like waiting for the server asynchronously.The `DialogService` (provided in the `AppModule` for app-wide use) does the asking. + +It returns a [promise](http://exploringjs.com/es6/ch_promises.html) that +*resolves* when the user eventually decides what to do: either +to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`). + + +{@a CanDeactivate} +Create a _guard_ that checks for the presence of a `canDeactivate` method in a component - any component. +The `CrisisDetailComponent` will have this method. +But the guard doesn't have to know that. +The guard shouldn't know the details of any component's deactivation method. +It need only detect that the component has a `canDeactivate` method and call it. +This approach makes the guard reusable. + + +{@example 'router/ts/src/app/can-deactivate-guard.service.ts'} + +Alternatively, You could make a component-specific `CanDeactivate` guard for the `CrisisDetailComponent`. The `canDeactivate` method provides you +with the current instance of the `component`, the current `ActivatedRoute` and `RouterStateSnapshot` in case you needed to access +some external information. This would be useful if you only wanted to use this guard for this component and needed to ask the component's +properties in or to confirm whether the router should allow navigation away from it. +Looking back at the `CrisisDetailComponent`, you have implemented the confirmation workflow for unsaved changes. +Notice that the `canDeactivate` method *can* return synchronously; +it returns `true` immediately if there is no crisis or there are no pending changes. +But it can also return a `Promise` or an `Observable` and the router will wait for that +to resolve to truthy (navigate) or falsy (stay put). +Add the `Guard` to the crisis detail route in `crisis-center-routing.module.ts` using the `canDeactivate` array. +Add the `Guard` to the main `AppRoutingModule` `providers` so the `Router` can inject it during the navigation process. + + +{@example 'router/ts/src/app/app-routing.module.4.ts'} + +Now you have given the user a safeguard against unsaved changes. +<a id="Resolve"></a> +<h3 id='resolve-guard'> + <i>Resolve</i>: pre-fetching component data +</h3> + +In the `Hero Detail` and `Crisis Detail`, you waited until the route was activated to fetch the respective hero or crisis. + +This worked well, but you can do better. +If you were using a real world api, there might be some delay before the data to display is returned from the server. +You don't want to display a blank component while waiting for the data. + +You prefer to pre-fetch data from the server so it's ready the moment the route is activated. +You'd like to handle errors before routing to the component. +There's no point in navigating to a crisis detail for an `id` that doesn't have a record. +You'd rather send the user back to the `Crisis List` where you only show valid crisis centers. + +In summary, you want to delay rendering the routed component until all necessary data have been fetched. + +You need a *resolver*. + +### Fetch data before navigating + +At the moment, the `CrisisDetailComponent` retrieves the selected crisis. +If the crisis is not found, it navigates back to the crisis list view. + +The experience might be better all of this were handled first, before the route is activated. +A `CrisisDetailResolver` service could retrieve a `Crisis` or navigate away if the `Crisis` does not existing +_before_ activating the route and creating the `CrisisDetailComponent`. + +Create the `crisis-detail-resolver.service.ts` file within the `Crisis Center` feature area. + + +{@example 'router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts'} + +Take the relevant parts of the crisis retrieval logic in `CrisisDetailComponent.ngOnInit` move them into the `CrisisDetailResolver`. +Import the `Crisis` model and `CrisisService` and also the `Router` so you can navigate elsewhere if you can't fetch the crisis. + +Be explicit. Implement the `Resolve` interface with a type of `Crisis`. + +Inject the `CrisisService` and `Router` and implement the `resolve` method. +That method could return a `Promise`, an `Observable`, or a synchronous return value. + +The `CrisisService.getCrisis` method returns a promise. +Return that promise to prevent the route from loading until the data is fetched. +If it doesn't return a valid `Crisis`, navigate the user back to the `CrisisListComponent`, +canceling the previous in-flight navigation to the `CrisisDetailComponent`. + +Import this resolver in the `crisis-center-routing.module.ts` and add a `resolve` object to the `CrisisDetailComponent` route configuration. + +Remember to add the `CrisisDetailResolver` service to the `CrisisCenterRoutingModule`'s `providers`. +The `CrisisDetailComponent` should no longer fetch the crisis. +Update the `CrisisDetailComponent` to get the crisis from the `ActivatedRoute.data.crisis` property instead; +that's where you said it should be when you re-configured the route. +It will be there when the `CrisisDetailComponent` ask for it. +**Two critical points** +1. The router's `Resolve` interface is optional. +The `CrisisDetailResolver` doesn't inherit from a base class. +The router looks for that method and calls it if found. + +1. Rely on the router to call the resolver. +Don't worry about all the ways that the user could navigate away. +That's the router's job. Write this class and let the router take it from there. + +The relevant *Crisis Center* code for this milestone follows. + +<md-tab-group> + + <md-tab label="app.component.ts"> + {@example 'router/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="crisis-center-home.component.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-center-home.component.ts'} + </md-tab> + + + <md-tab label="crisis-center.component.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-center.component.ts'} + </md-tab> + + + <md-tab label="crisis-center-routing.module.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-center-routing.module.4.ts'} + </md-tab> + + + <md-tab label="crisis-list.component.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-list.component.ts'} + </md-tab> + + + <md-tab label="crisis-detail.component.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-detail.component.ts'} + </md-tab> + + + <md-tab label="crisis-detail-resolver.service.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts'} + </md-tab> + + + <md-tab label="crisis.service.ts"> + {@example 'router/ts/src/app/crisis-center/crisis.service.ts'} + </md-tab> + + +</md-tab-group> + + +<md-tab-group> + + <md-tab label="auth-guard.service.ts"> + {@example 'router/ts/src/app/auth-guard.service.3.ts'} + </md-tab> + + + <md-tab label="can-deactivate-guard.service.ts"> + {@example 'router/ts/src/app/can-deactivate-guard.service.ts'} + </md-tab> + + +</md-tab-group> + + + +{@a query-parameters} + + +{@a fragment} +### Query parameters and fragments + +In the [route parameters](#optional-route-parameters) example, you only dealt with parameters specific to +the route, but what if you wanted optional parameters available to all routes? +This is where query parameters come into play. + +[Fragments](https://en.wikipedia.org/wiki/Fragment_identifier) refer to certain elements on the page +identified with an `id` attribute. + +Update the `AuthGuard` to provide a `session_id` query that will remain after navigating to another route. + +Add an `anchor` element so you can jump to a certain point on the page. + +Add the `NavigationExtras` object to the `router.navigate` method that navigates you to the `/login` route. +You can also preserve query parameters and fragments across navigations without having to re-provide them +when navigating. In the `LoginComponent`, you'll add an *object* as the second argument in the `router.navigate` function +and provide the `preserveQueryParams` and `preserveFragment` to pass along the current query parameters +and fragment to the next route. +Since you'll be navigating to the *Admin Dashboard* route after logging in, you'll update it to handle the +query parameters and fragment. +*Query Parameters* and *Fragments* are also available through the `ActivatedRoute` service. +Just like *route parameters*, the query parameters and fragments are provided as an `Observable`. +The updated *Crisis Admin* component feeds the `Observable` directly into the template using the `AsyncPipe`. +Following the steps in this process, you can click on the *Admin* button, that takes you to the *Login* +page with the provided `query params` and `fragment`. After you click the login button, notice that +you have been redirected to the `Admin Dashboard` page with the `query params` and `fragment` still intact. + +You can use these persistent bits of information for things that need to be provided with across pages interaction like +authentication tokens or session ids. + +The `query params` and `fragment` can also be preserved using a `RouterLink` with +the `preserveQueryParams` and `preserveFragment` bindings respectively. + +## Milestone 6: Asynchronous routing + +As you have completed the milestones, the application has naturally gotten larger. +As you continue to build out feature areas, the overall application size will get larger also. +At some point you'll reach a tipping point where the application takes long time to load. + +How do you combat this problem? With asynchronous routing which loads feature modules _lazily_, on request. +Lazy loading has multiple benefits. + +* You can load feature areas only when requested by the user. +* You can speed up load time for users that only visit certain areas of the application. +* You can continue expanding lazy-loaded feature areas without increasing the size of the initial load bundle. + +You're already made part way there. +By organizing the application into modules — +`AppModule`, `HeroesModule`, `AdminModule` and `CrisisCenterModule` — you have natural candidates for lazy-loading. + +Some modules, like `AppModule`, must be loaded from the start. +But other can and should be lazy-loaded. +The `AdminModule`, for example, is needed by a few, authorized users, +You should only load it when requested by the right people. +### Lazy-Loading route configuration + +Change the `admin` **path** in the `admin-routing.module.ts` from `'admin'` to an empty string, `''`, the _empty path_. + +The `Router` supports *empty path* routes; +use them to group routes together without adding any additional path segments to the URL. +Users will still visit `/admin` and the `AdminComponent` still serves as the *Routing Component* containing child routes. + +Open the `AppRoutingModule` and add a new `admin` route to its `appRoutes` array. + +Give it a `loadChildren` property (not a `children` property!), set to the address of the `AdminModule`. +The address is the `AdminModule` file location (relative to the app root), +followed by a `#` separator, +followed by the name of the exported module class, `AdminModule`. + + +{@example 'router/ts/src/app/app-routing.module.5.ts' region='admin-1'} + +When the router navigates to this route, it uses the `loadChildren` string to dynamically load the `AdminModule`. +Then it adds the `AdminModule` routes to its current route configuration. +Finally, it loads the requested route to the destination admin component. + +The lazy loading and re-configuration happen just once, when the route is _first_ requested; +the module and routes are available immediately for subsequent requests. + +Angular provides a built-in module loader that supports SystemJS to load modules asynchronously. If you were +using another bundling tool, such as Webpack, you would use the Webpack mechanism for asynchronously loading modules. +Take the final step and detach the admin feature set from the main application. +The root `AppModule` must neither load nor reference the `AdminModule` or its files. + +In the `app.module.ts`, remove the `AdminModule` import statement from the top of the file +and remove the `AdminModule` from the Angular module's `imports` array. + +<h3 id='can-load-guard'> + <i>CanLoad Guard</i>: guarding unauthorized loading of feature modules +</h3> + +You're already protecting the `AdminModule` with a `CanActivate` guard that prevents unauthorized users from +accessing the admin feature area. +It redirects to the login page if the user is not authorized. + +But the router is still loading the `AdminModule` even if the user can't visit any of its components. +Ideally, you's only load the `AdminModule` if the user is logged in. + +Add a **`CanLoad`** guard that only loads the `AdminModule` once the user is logged in _and_ attempts to access the admin feature area. + +The existing _`AuthGuard`_ already has the essential logic, in its `checkLogin` method, to support the `CanLoad` guard. + +Open the `auth-guard.service.ts`. +Import the `CanLoad` interface from '@angular/router'. +Add it to the `AuthGuard` class's `implements` list. +Then implement `canLoad` as follows: +The router sets the `canLoad` methods `route` parameter to the intended destination URL. +The `checkLogin` method redirects to that URL once the user has logged in. + +Now import the `AuthGuard` into the `AppRoutingModule` and add the `AuthGuard` to the `canLoad` array for the `admin` route. +The completed admin route looks like this. + + +{@example 'router/ts/src/app/app-routing.module.5.ts' region='admin'} + + + +{@a preloading} +### _Preloading_: background loading of feature areas +You've learned how to load modules on-demand. +You can also load modules asynchronously with _preloading_. + +This may seem like what the app has been doing all along. Not quite. +The `AppModule` for instance is loaded when the application starts; that's _eager_ loading. +Now the `AdminModule` loads only when the user clicks on a link; that's _lazy_ loading. + +_Preloading_ is something in between. +Consider the _Crisis Center_. +It isn't the first view that a user sees. +By default, the _Heroes_ are the first view. +For the smallest initial payload and fastest launch time, +you should eagerly load the `AppModule` and the `HeroesModule`. + +You could lazy load the _Crisis Center_. +But you're almost certain that the user will visit the _Crisis Center_ within minutes of launching the app. +Ideally, the app would launch with just the `AppModule` and the `HeroesModule` loaded +and then, almost immediately, load the `CrisisCenterModule` in the background. +By the time the user navigates to the _Crisis Center_, its module will have been loaded and ready to go. + +That's _preloading_. + +#### How it works + +After each _successful_ navigation, the router looks in its configuration for an unloaded module that it can preload. +Whether it preloads a module and which modules it preloads depends upon the *preload strategy*. + +The `Router` offers two preloading strategies out of the box: + +* No preloading at all which is the default. Lazy loaded feature areas are still loaded on demand. +* Preloading of all lazy loaded feature areas. + +Out of the box, the router either never preloads, or preloads every lazy-load module. +The `Router` also supports [custom preloading strategies](#custom-preloading) for fine control over which modules to preload and when. + +In this next section, you'll update the `CrisisCenterModule` to load lazily by default and use the `PreloadAllModules` strategy +to load it (and _all other_ lazy loaded modules) as soon as possible. + +#### Lazy load the _crisis center_ + +Update the route configuration to lazy load the `CrisisCenterModule`. +Take the same steps you used to configure `AdminModule` for lazy load. + +1. Change the `crisis-center` path in the `CrisisCenterRoutingModule` to an empty string. + +1. Add a `crisis-center` route to the `AppRoutingModule`. + +1. Set the `loadChildren` string to load the `CrisisCenterModule`. + +1. Remove all mention of the `CrisisCenterModule` from `app.module.ts`. + +Here are the updated modules _before enabling preload_: + +<md-tab-group> + + <md-tab label="app.module.ts"> + {@example 'router/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="app-routing.module.ts"> + {@example 'router/ts/src/app/app-routing.module.6.ts' region='preload-v1'} + </md-tab> + + + <md-tab label="crisis-center-routing.module.ts"> + {@example 'router/ts/src/app/crisis-center/crisis-center-routing.module.ts'} + </md-tab> + + +</md-tab-group> + +You could try this now and confirm that the `CrisisCenterModule` loads after you click the "Crisis Center" button. + +To enable preloading of all lazy loaded modules, import the `PreloadAllModules` token from the Angular router package. + +The second argument in the `RouterModule.forRoot` method takes an object for additional configuration options. +The `preloadingStrategy` is one of those options. +Add the `PreloadAllModules` token to the `forRoot` call:This tells the `Router` preloader to immediately load _all_ lazy-loaded routes (routes with a `loadChildren` property). + +When you visit `http://localhost:3000`, the `/heroes` route loads immediately upon launch. +and the router starts loading the `CrisisCenterModule` right after the `HeroesModule` loads. + +Surprisingly, the `AdminModule` does _not_ preload. Something is blocking it. + + +{@a preload-canload} +#### CanLoad blocks preload + +The `PreloadAllModules` strategy does not load feature areas protected by a [CanLoad](#can-load-guard) guard. +This is by design. + +You added a `canLoad` guard to the route to the `AdminModule` a few steps back +to block loading of that module until the user is authorized. +That `canLoad` guard takes precedence over the preload strategy. + +If you want both to preload a module and guard against unauthorized access, +drop the `canLoad` guard and rely on the [CanActivate](#can-activate-guard) guard alone. + + +{@a custom-preloading} +### Custom Preloading Strategy + +Preloading every lazy loaded modules works well in many situations, +but it isn't always the right choice, especially on mobile devices and over low bandwidth connections. +You may choose to preload only certain feature modules, based on user metrics and other business and technical factors. + +You can control what and how the router preloads with a custom preloading strategy. + +In this section, you'll add a custom strategy that _only_ preloads routes whose `data.preload` flag is set to `true`. +Recall that you can add anything to the `data` property of a route. + +Set the `data.preload` flag in the `crisis-center` route in the `AppRoutingModule`. +Add a new file to the project called `selective-preloading-strategy.ts` +and define a `SelectivePreloadingStrategy` service class as follows:`SelectivePreloadingStrategy` implements the `PreloadingStrategy`, which has one method, `preload`. + +The router calls the `preload` method with two arguments +1. The route to consider. +1. A loader function that can load the routed module asynchronously. + +An implementation of `preload`must return an `Observable`. +If the route should preload, it returns the observable returned by calling the loader function. +If the route should _not_ preload, it returns an `Observable` of `null`. + +In this sample, the `preload` method loads the route if the route's `data.preload` flag is truthy. + +It also has a side-effect. +`SelectivePreloadingStrategy` logs the `path` of a selected route in its public `preloadedModules` array. + +Shortly, you'll extend the `AdminDashboardComponent` to inject this service and display its `preloadedModules` array. + +But first, make a few changes to the `AppRoutingModule`. +1. Import `SelectivePreloadingStrategy` into `AppRoutingModule`. +1. Replace the `PreloadAllModules` strategy in the call to `forRoot` with this `SelectivePreloadingStrategy`. +1. Add the `SelectivePreloadingStrategy` strategy to the `AppRoutingModule` providers array so it can be injected +elsewhere in the app. + +Now edit the `AdminDashboardComponent` to display the log of preloaded routes. +1. Import the `SelectivePreloadingStrategy` (it's a service) +1. Inject it into the dashboard's constructor. +1. Update the template to display the strategy service's `preloadedModules` array. + +When you're done it looks like this. +Once the application loads the initial route, the `CrisisCenterModule` is preloaded. +Verify this by logging in to the `Admin` feature area and noting that the `crisis-center` is listed in the `Preloaded Modules`. +It's also logged to the browser's console. + + +{@a inspect-config} + +## Inspect the router's configuration + +You put a lot of effort into configuring the router in several routing module files +and were careful to list them [in the proper order](#routing-module-order). +Are routes actually evaluated as you planned? +How is the router really configured? + +You can inspect the router's current configuration any time by injecting it and +examining its `config` property. +For example, update the `AppModule` as follows and look in the browser console window +to see the finished route configuration. + +{@a final-app} + +## Wrap Up + +You've covered a lot of ground in this guide and the application is too big to reprint here. +Please visit the <live-example title="Router Sample in Plunker"></live-example> and +where you can download the final source code. + +## Appendices + +The balance of this guide is a set of appendices that +elaborate some of the points you covered quickly above. + +The appendix material isn't essential. Continued reading is for the curious. + +## Appendix: Link parameters array + +A link parameters array holds the ingredients for router navigation: + +* the *path* of the route to the destination component +* required and optional route parameters that go into the route URL + +You can bind the `RouterLink` directive to such an array like this: +You've written a two element array when specifying a route parameter like this +You can provide optional route parameters in an object like this: +These three examples cover the need for an app with one level routing. +The moment you add a child router, such as the crisis center, you create new link array possibilities. + +Recall that you specified a default child route for crisis center so this simple `RouterLink` is fine. +Parse it out. + +* The first item in the array identifies the parent route (`/crisis-center`). +* There are no parameters for this parent route so you're done with it. +* There is no default for the child route so you need to pick one. +* You're navigating to the `CrisisListComponent`, whose route path is `/`, but you don't need to explicitly add the slash +* Voila! `['/crisis-center']`. + +Take it a step further. Consider the following router link that +navigates from the root of the application down to the *Dragon Crisis*: +* The first item in the array identifies the parent route (`/crisis-center`). +* There are no parameters for this parent route so you're done with it. +* The second item identifies the child route details about a particular crisis (`/:id`). +* The details child route requires an `id` route parameter. +* You added the `id` of the *Dragon Crisis* as the second item in the array (`1`). +* The resulting path is `/crisis-center/1`. +If you wanted to, you could redefine the `AppComponent` template with *Crisis Center* routes exclusively: +In sum, you can write applications with one, two or more levels of routing. +The link parameters array affords the flexibility to represent any routing depth and +any legal sequence of route paths, (required) router parameters and (optional) route parameter objects. + + +{@a browser-url-styles} + +## Appendix: *LocationStrategy* and browser URL styles + +When the router navigates to a new component view, it updates the browser's location and history +with a URL for that view. +This is a strictly local URL. The browser shouldn't send this URL to the server +and should not reload the page. + +Modern HTML 5 browsers support +<a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries" target="_blank" title="HTML5 browser history push-state">history.pushState</a>, +a technique that changes a browser's location and history without triggering a server page request. +The router can compose a "natural" URL that is indistinguishable from +one that would otherwise require a page load. + +Here's the *Crisis Center* URL in this "HTML 5 pushState" style: + +<code-example format="nocode"> + localhost:3002/crisis-center/ + +</code-example> + +Older browsers send page requests to the server when the location URL changes ... +unless the change occurs after a "#" (called the "hash"). +Routers can take advantage of this exception by composing in-application route +URLs with hashes. Here's a "hash URL" that routes to the *Crisis Center* + +<code-example format="nocode"> + localhost:3002/src/#/crisis-center/ + +</code-example> + +The router supports both styles with two `LocationStrategy` providers: + +1. `PathLocationStrategy` - the default "HTML 5 pushState" style. +1. `HashLocationStrategy` - the "hash URL" style. + +The `RouterModule.forRoot` function sets the `LocationStrategy` to the `PathLocationStrategy`, +making it the default strategy. +You can switch to the `HashLocationStrategy` with an override during the bootstrapping process if you prefer it. + +Learn about "providers" and the bootstrap process in the +[Dependency Injection guide](dependency-injection.html#bootstrap) +### Which strategy is best? + +You must choose a strategy and you need to make the right call early in the project. +It won't be easy to change later once the application is in production +and there are lots of application URL references in the wild. + +Almost all Angular projects should use the default HTML 5 style. +It produces URLs that are easier for users to understand. +And it preserves the option to do _server-side rendering_ later. + +Rendering critical pages on the server is a technique that can greatly improve +perceived responsiveness when the app first loads. +An app that would otherwise take ten or more seconds to start +could be rendered on the server and delivered to the user's device +in less than a second. + +This option is only available if application URLs look like normal web URLs +without hashes (#) in the middle. + +Stick with the default unless you have a compelling reason to +resort to hash routes. + +### HTML 5 URLs and the *<base href>* + +While the router uses the +<a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries" target="_blank" title="Browser history push-state">HTML 5 pushState</a> +style by default, you *must* configure that strategy with a **base href** + +The preferred way to configure the strategy is to add a +<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base" target="_blank" title="base href"><base href> element</a> +tag in the `<head>` of the `index.html`. +Without that tag, the browser may not be able to load resources +(images, css, scripts) when "deep linking" into the app. +Bad things could happen when someone pastes an application link into the +browser's address bar or clicks such a link in an email link. + +Some developers may not be able to add the `<base>` element, perhaps because they don't have +access to `<head>` or the `index.html`. + +Those developers may still use HTML 5 URLs by taking two remedial steps: + +1. Provide the router with an appropriate [APP_BASE_HREF][] value. +1. Use _root URLs_ for all web resources: css, images, scripts, and template html files. + +[APP_BASE_HREF]: ../api/common/index/APP_BASE_HREF-let.html +### *HashLocationStrategy* + +You can go old-school with the `HashLocationStrategy` by +providing the `useHash: true` in an object as the second argument of the `RouterModule.forRoot` +in the `AppModule`. diff --git a/aio/content/guide/security.md b/aio/content/guide/security.md new file mode 100644 index 0000000000..ef217e3581 --- /dev/null +++ b/aio/content/guide/security.md @@ -0,0 +1,142 @@ +@title +Security + +@intro +Developing for content security in Angular applications + +@description +This section describes Angular's built-in +protections against common web application vulnerabilities and attacks such as cross-site +scripting attacks. It does not cover application-level security, such as authentication (_Who is +this user?_) or authorization (_What can this user do?_). + +For more information about the attacks and mitigations described below, see [OWASP Guide Project](https://www.owasp.org/index.php/Category:OWASP_Guide_Project). +Try the <live-example></live-example> of the code shown in this page. + + +<h2 id='report-issues'> + Reporting vulnerabilities +</h2> + +Email us at [security@angular.io](mailto:security@angular.io) to report vulnerabilities in +Angular itself. + +For more information about how Google handles security issues, see [Google's security +philosophy](https://www.google.com/about/appsecurity/). + + +<h2 id='best-practices'> + Best practices +</h2> + +* **Keep current with the latest Angular library releases.** +We regularly update our Angular libraries, and these updates may fix security defects discovered in +previous versions. Check the Angular [change +log](https://github.com/angular/angular/blob/master/CHANGELOG.md) for security-related updates. + +* **Don't modify your copy of Angular.** +Private, customized versions of Angular tend to fall behind the current version and may not include +important security fixes and enhancements. Instead, share your Angular improvements with the +community and make a pull request. + +* **Avoid Angular APIs marked in the documentation as “[_Security Risk_](#bypass-security-apis).”** + + +<h2 id='xss'> + Preventing cross-site scripting (XSS) +</h2> + +[Cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) enables attackers +to inject malicious code into web pages. Such code can then, for example, steal user data (in +particular, their login data) or perform actions impersonating the user. This is one of the most +common attacks on the web. + +To block XSS attacks, you must prevent malicious code from entering the DOM (Document Object Model). For example, if an +attacker can trick you into inserting a `<script>` tag in the DOM, they can run arbitrary code on +your website. The attack is not limited to `<script>` tags—many elements and properties in the +DOM allow code execution, for example, `<img onerror="...">` and `<a href="javascript:...">`. If +attacker-controlled data enters the DOM, expect security vulnerabilities. + +### Angular’s cross-site scripting security model + +To systematically block XSS bugs, Angular treats all values as untrusted by default. When a value +is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation, Angular sanitizes and escapes untrusted values. + +_Angular templates are the same as executable code_: HTML, attributes, and binding expressions +(but not the values bound!) in templates are trusted to be safe. This means that applications must +prevent values that an attacker can control from ever making it into the source code of a +template. Never generate template source code by concatenating user input and templates! Using +the [offline template compiler](#offline-template-compiler) is an effective way to prevent these +vulnerabilities, also known as _template injection_. + +### Sanitization and security contexts + +_Sanitization_ is the inspection of an untrusted value, turning it into a value that is safe to insert into +the DOM. In many cases, sanitization does not change a value at all. Sanitization depends on context: +a value that is harmless in CSS is potentially dangerous in a URL. + +Angular defines four security contexts—HTML, style, URL, and resource URL: + +* **HTML** is used when interpreting a value as HTML, for example, when binding to `innerHtml` +* **Style** is used when binding CSS into the `style` property +* **URL** is used for URL properties such as `<a href>` +* **Resource URL** is a URL that will be loaded and executed as code, for example, in `<script src>` + +Angular sanitizes untrusted values for the first three items; sanitizing resource URLs is not +possible because they contain arbitrary code. In development mode, Angular prints a console warning +when it has to change a value during sanitization. + +### Sanitization example + +The template below binds the value of `htmlSnippet`, once by interpolating it into an element's +content, and once by binding it to the `innerHTML` property of an element: + + +{@example 'security/ts/src/app/inner-html-binding.component.html'} + +Interpolated content is always escaped—the HTML is not interpreted, and the browser displays +angle brackets in the element's text content. + +For the HTML to be interpreted, you must bind it to an HTML property such as `innerHTML`. But binding +a value that an attacker might control into `innerHTML` normally causes an XSS +vulnerability. For example, code contained in a `<script>` tag is executed: +### Avoid direct use of the DOM APIs + +The built-in browser DOM APIs do not automatically protect you from security vulnerabilities. +For example, `document`, the node available through `ElementRef`, and many third-party APIs +contain unsafe methods. Avoid directly interacting with the DOM and instead use Angular +templates where possible. + +### Content security policy + +[Content Security Policy (CSP)](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) is a defense-in-depth +technique to prevent XSS. To enable CSP, configure your web server to return an appropriate +`Content-Security-Policy` HTTP header. + +<a id="offline-template-compiler"></a> +### Use the offline template compiler + +The offline template compiler prevents a whole class of vulnerabilities called template injection, +and also greatly improves application performance. Use the offline template compiler in production +deployments; do not dynamically generate templates. Angular trusts template code, so generating +templates, in particular templates containing user data, circumvents Angular's built-in protections. For information about how to dynamically construct forms in a safe way, see +[Dynamic Forms Cookbook](../cookbook/dynamic-form.html). + +### Server-side XSS protection + +HTML constructed on the server is vulnerable to injection attacks. Injecting template code into an +Angular application is the same as injecting executable code into the +application: it gives the attacker full control over the application. To prevent this, +use a templating language that automatically escapes values to prevent XSS vulnerabilities on +the server. Do not generate Angular templates on the server side using a templating language; doing this +carries a high risk of introducing template-injection vulnerabilities. + + +<h2 id='code-review'> + Auditing angular applications +</h2> + +Angular applications must follow the same security principles as regular web applications, and +must be audited as such. Angular-specific APIs that should be audited in a security review, +such as the [_bypassSecurityTrust_](#bypass-security-apis) methods, are marked in the documentation +as security sensitive. \ No newline at end of file diff --git a/aio/content/guide/server-communication.md b/aio/content/guide/server-communication.md new file mode 100644 index 0000000000..37b65807b2 --- /dev/null +++ b/aio/content/guide/server-communication.md @@ -0,0 +1,390 @@ +@title +HTTP Client + +@intro +Use an HTTP Client to talk to a remote server. + +@description +[HTTP](https://tools.ietf.org/html/rfc2616) is the primary protocol for browser/server communication. +The [`WebSocket`](https://tools.ietf.org/html/rfc6455) protocol is another important communication technology; +it isn't covered in this page.Modern browsers support two HTTP-based APIs: +[XMLHttpRequest (XHR)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) and +[JSONP](https://en.wikipedia.org/wiki/JSONP). A few browsers also support +[Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). + +The !{_Angular_http_library} simplifies application programming with the **XHR** and **JSONP** APIs. +This page covers: + +- [The Tour of Heroes *HTTP* client demo](#http-client). +- [Fetch data with http.get](#fetch-data). +<li if-docs="ts"> [RxJS library](#rxjs).</li> +<li if-docs="ts"> [Enable RxJS operators](#enable-rxjs-operators).</li> +- [Process the response object](#extract-data). +- [Always handle errors](#error-handling). +- [Send data to the server](#update). +<li if-docs="ts"> [Fall back to promises](#promises).</li> +- [Cross-Origin Requests: Wikipedia example](#cors). + <ul if-docs="ts"> + <li> [Search parameters](#search-parameters).</li> + <li> [More fun with observables](#more-observables).</li> + </ul> +- [Guarding against Cross-Site Request Forgery](#xsrf). +- [Override default request headers (and other request options)](#override-default-request-options). +- [Appendix: Tour of Heroes _in-memory web api_](#in-mem-web-api). + +A <live-example>live example</live-example> illustrates these topics. + +# Demos + +This page describes server communication with the help of the following demos: +The root `AppComponent` orchestrates these demos: + +{@example 'server-communication/ts/src/app/app.component.ts'} + + +# Providing HTTP services + +First, configure the application to use server communication facilities. + +The !{_Angular_Http} client communicates with the server using a familiar HTTP request/response protocol. +The `!{_Http}` client is one of a family of services in the !{_Angular_http_library}. +Before you can use the `!{_Http}` client, you need to register it as a service provider with the dependency injection system. + +Read about providers in the [Dependency Injection](dependency-injection.html) page. +Register providers by importing other NgModules to the root NgModule in `app.module.ts`. + + +{@example 'server-communication/ts/src/app/app.module.1.ts'} + + +The `HttpModule` is necessary for making HTTP calls. +Though the JsonpModule isn't necessary for plain HTTP, +there is a JSONP demo later in this page. +Loading its module now saves time. +## The Tour of Heroes HTTP client demo + +The first demo is a mini-version of the [tutorial](../tutorial)'s "Tour of Heroes" (ToH) application. +This version gets some heroes from the server, displays them in a list, lets the user add new heroes, and saves them to the server. +The app uses the !{_Angular_Http} client to communicate via `XMLHttpRequest (XHR)`. + +It works like this: +<figure class='image-display'> + <img src='/resources/images/devguide/server-communication/http-toh.gif' alt="ToH mini app" width="250"> </img> +</figure> + +This demo has a single component, the `HeroListComponent`. Here's its template: + +{@example 'server-communication/ts/src/app/toh/hero-list.component.html'} + +It presents the list of heroes with an `ngFor`. +Below the list is an input box and an *Add Hero* button where you can enter the names of new heroes +and add them to the database. +A [template reference variable](template-syntax.html#ref-vars), `newHeroName`, accesses the +value of the input box in the `(click)` event binding. +When the user clicks the button, that value passes to the component's `addHero` method and then +the event binding clears it to make it ready for a new hero name. + +Below the button is an area for an error message. + + +{@a oninit} + + +{@a HeroListComponent} +### The *HeroListComponent* class +Here's the component class: + +{@example 'server-communication/ts/src/app/toh/hero-list.component.ts' region='component'} + +Angular [injects](dependency-injection.html) a `HeroService` into the constructor +and the component calls that service to fetch and save data. + +The component **does not talk directly to the !{_Angular_Http} client**. +The component doesn't know or care how it gets the data. +It delegates to the `HeroService`. + +This is a golden rule: **always delegate data access to a supporting service class**. + +Although _at runtime_ the component requests heroes immediately after creation, +you **don't** call the service's `get` method in the component's constructor. +Instead, call it inside the `ngOnInit` [lifecycle hook](lifecycle-hooks.html) +and rely on Angular to call `ngOnInit` when it instantiates this component. +This is a *best practice*. +Components are easier to test and debug when their constructors are simple, and all real work +(especially calling a remote server) is handled in a separate method.With a basic understanding of the component, you're ready to look inside the `HeroService`. + + +{@a HeroService} + +## Fetch data with http.get + +In many of the previous samples the app faked the interaction with the server by +returning mock heroes in a service like this one: + +{@example 'toh-4/ts/src/app/hero.service.ts' region='just-get-heroes'} + +You can revise that `HeroService` to get the heroes from the server using the !{_Angular_Http} client service: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='v1'} + +Notice that the !{_Angular_Http} client service is +[injected](dependency-injection.html) into the `HeroService` constructor. + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='ctor'} + +Look closely at how to call `!{_priv}http.get`: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='http-get'} + +You pass the resource URL to `get` and it calls the server which returns heroes. + +The server returns heroes once you've set up the [in-memory web api](#in-mem-web-api) +described in the appendix below. +Alternatively, you can temporarily target a JSON file by changing the endpoint URL: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='endpoint-json'} + + + + +{@a extract-data} +## Process the response object +Remember that the `getHeroes()` method used an `!{_priv}extractData` helper method to map the `!{_priv}http.get` response object to heroes: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='extract-data'} + +The `response` object doesn't hold the data in a form the app can use directly. +You must parse the response data into a JSON object. + +### Parse to JSON +Don't expect the decoded JSON to be the heroes !{_array} directly. +This server always wraps JSON results in an object with a `data` +property. You have to unwrap it to get the heroes. +This is conventional web API behavior, driven by +[security concerns](https://www.owasp.org/index.php/OWASP_AJAX_Security_Guidelines#Always_return_JSON_with_an_Object_on_the_outside). + + +~~~ {.alert.is-important} + +Make no assumptions about the server API. +Not all servers return an object with a `data` property. + +~~~ + +### Do not return the response object +The `getHeroes()` method _could_ have returned the HTTP response but this wouldn't +be a best practice. +The point of a data service is to hide the server interaction details from consumers. +The component that calls the `HeroService` only wants heroes and is kept separate +from getting them, the code dealing with where they come from, and the response object. + + +{@a error-handling} +### Always handle errors + +An important part of dealing with I/O is anticipating errors by preparing to catch them +and do something with them. One way to handle errors is to pass an error message +back to the component for presentation to the user, +but only if it says something that the user can understand and act upon. + +This simple app conveys that idea, albeit imperfectly, in the way it handles a `getHeroes` error. + + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='error-handling'} + + + +{@a subscribe} + + +{@a hero-list-component} + +<h3> + <b> HeroListComponent </b> error handling +</h3> + + + +{@example 'server-communication/ts/src/app/toh/hero-list.component.ts' region='getHeroes'} + + +Want to see it fail? In the `HeroService`, reset the api endpoint to a bad value. Afterward, remember to restore it. + +<a id="update"></a> +<a id="post"></a> +## Send data to the server + +So far you've seen how to retrieve data from a remote location using an HTTP service. +Now you'll add the ability to create new heroes and save them in the backend. + +You'll write a method for the `HeroListComponent` to call, an `addHero()` method, that takes +just the name of a new hero and returns an `Observable` of `Hero`. It begins like this: + + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero-sig'} + +To implement it, you must know the server's API for creating heroes. + +[This sample's data server](#server) follows typical REST guidelines. +It expects a [`POST`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) request +at the same endpoint as `GET` heroes. +It expects the new hero data to arrive in the body of the request, +structured like a `Hero` entity but without the `id` property. +The body of the request should look like this: + +<code-example format="." language="javascript"> + { "name": "Windstorm" } +</code-example> + +The server generates the `id` and returns the entire `JSON` representation +of the new hero including its generated id. The hero arrives tucked inside a response object +with its own `data` property. + +Now that you know how the API works, implement `addHero()`as follows: + + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'} + +### Headers + +In the `headers` object, the `Content-Type` specifies that the body represents JSON. +### JSON results + +As with `getHeroes()`, use the `!{_priv}extractData()` helper to [extract the data](#extract-data) +from the response. + + +{@example 'server-communication/ts/src/app/toh/hero-list.component.ts' region='addHero'} + + +<h2 id='cors'> + Cross-Origin Requests: Wikipedia example +</h2> + +You just learned how to make `XMLHttpRequests` using the !{_Angular_Http} service. +This is the most common approach for server communication, but it doesn't work in all scenarios. + +For security reasons, web browsers block `XHR` calls to a remote server whose origin is different from the origin of the web page. +The *origin* is the combination of URI scheme, hostname, and port number. +This is called the [same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy). + +Modern browsers do allow `XHR` requests to servers from a different origin if the server supports the +[CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) protocol. +If the server requires user credentials, you'll enable them in the [request headers](#headers). +Some servers do not support CORS but do support an older, read-only alternative called [JSONP](https://en.wikipedia.org/wiki/JSONP). +Wikipedia is one such server. +This [Stack Overflow answer](http://stackoverflow.com/questions/2067472/what-is-jsonp-all-about/2067584#2067584) covers many details of JSONP.### Search wikipedia + +Here is a simple search that shows suggestions from Wikipedia as the user +types in a text box: + +<figure class='image-display'> + <img src='/resources/images/devguide/server-communication/wiki-1.gif' alt="Wikipedia search app (v.1)" width="250"> </img> +</figure> + + + +{@a xsrf} + +## Guarding against Cross-Site Request Forgery + +In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting +a different web page with malignant code that secretly sends a malicious request to your application's web server, + +The server and client application must work together to thwart this attack. +Angular's `Http` client does its part by applying a default `CookieXSRFStrategy` automatically to all requests. + +The `CookieXSRFStrategy` supports a common anti-XSRF technique in which the server sends a randomly +generated authentication token in a cookie named `XSRF-TOKEN`. +The HTTP client adds an `X-XSRF-TOKEN` header with that token value to subsequent requests. +The server receives both the cookie and the header, compares them, and processes the request only if the cookie and header match. + +See the [XSRF topic on the Security page](security.html#xsrf) for more information about XSRF and Angular's `XSRFStrategy` counter measures. + + +{@a override-default-request-options} + +## Override default request headers (and other request options) + +Request options (such as headers) are merged into the +[default _RequestOptions_](https://angular.io/docs/ts/latest/api/http/index/BaseRequestOptions-class.html "API: BaseRequestOptions") +before the request is processed. +The `HttpModule` provides these default options via the `RequestOptions` token. + +You can override these defaults to suit your application needs. +by creating a custom sub-class of `RequestOptions` +that sets the default options for the application. + +This sample creates a class that sets the default `Content-Type` header to JSON. +It exports a constant with the necessary `RequestOptions` provider to simplify registration in `AppModule`. + + +{@example 'server-communication/ts/src/app/default-request-options.service.ts'} + +Then it registers the provider in the root `AppModule`. + +{@example 'server-communication/ts/src/app/app.module.ts' region='provide-default-request-options'} + + +Remember to include this provider during setup when unit testing the app's HTTP services.After this change, the `header` option setting in `HeroService.addHero` is no longer necessary, + + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='addhero'} + +You can confirm that `DefaultRequestOptions` is working by examing HTTP requests in the browser developer tools' network tab. +If you're short-circuiting the server call with something like the [_in-memory web api_](#in-mem-web-api), +try commenting-out the `addHero` header option, +set a breakpoint on the POST call, and step through the request processing +to verify the header is there. + +Individual requests options, like this one, take precedence over the default `RequestOptions`. +It might be wise to keep the `addHero` request header setting for extra safety. + + +{@a in-mem-web-api} + +## Appendix: Tour of Heroes _in-memory web api_ + +If the app only needed to retrieve data, you could get the heroes from a `heroes.json` file: +You wrap the heroes array in an object with a `data` property for the same reason that a data server does: +to mitigate the [security risk](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk) +posed by top-level JSON arrays.You'd set the endpoint to the JSON file like this: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='endpoint-json'} + +The *get heroes* scenario would work, +but since the app can't save changes to a JSON file, it needs a web API server. +Because there isn't a real server for this demo, +it substitutes the Angular _in-memory web api_ simulator for the actual XHR backend service. + +The in-memory web api is not part of Angular _proper_. +It's an optional service in its own +<a href="https://github.com/angular/in-memory-web-api" target="_blank" title="In-memory Web API"><i>angular-in-memory-web-api</i></a> +library installed with npm (see `package.json`). + +See the +<a href="https://github.com/angular/in-memory-web-api/blob/master/README.md" target="_blank" title='In-memory Web API "README.md"'><i>README file</i></a> +for configuration options, default behaviors, and limitations. +The in-memory web API gets its data from !{_a_ca_class_with} a `createDb()` +method that returns a map whose keys are collection names and whose values +are !{_array}s of objects in those collections. + +Here's the class for this sample, based on the JSON data: + +{@example 'server-communication/ts/src/app/hero-data.ts'} + +Ensure that the `HeroService` endpoint refers to the web API: + +{@example 'server-communication/ts/src/app/toh/hero.service.ts' region='endpoint'} + +Here is the final, revised version of <span ngio-ex>src/app/app.module.ts</span>, demonstrating these steps. + + +~~~ {.alert.is-important} + +Import the `InMemoryWebApiModule` _after_ the `HttpModule` to ensure that +the `XHRBackend` provider of the `InMemoryWebApiModule` supersedes all others. + +~~~ + +See the full source code in the <live-example></live-example>. \ No newline at end of file diff --git a/aio/content/guide/setup.md b/aio/content/guide/setup.md new file mode 100644 index 0000000000..615dd0093c --- /dev/null +++ b/aio/content/guide/setup.md @@ -0,0 +1,223 @@ +@title +Setup for local development + +@intro +Install the Angular QuickStart seed for faster, more efficient development on your machine + +@description + + +{@a develop-locally} +## Setup a local development environment + +<span if-docs="ts"> +The <live-example name=quickstart>QuickStart live-coding</live-example> example is an Angular _playground_. +It's not where you'd develop a real application. +You [should develop locally](#why-locally "Why develop locally") on your own machine ... and that's also how we think you should learn Angular. +</span> + +Setting up a new project on your machine is quick and easy with the **QuickStart seed**, +maintained [on github](!{_qsRepo} "Install the github QuickStart repo"). +Make sure you have [!{_prereq} installed](#install-prerequisites "What if you don't have !{_prereq}?"). +Then ... +1. Create a project folder (you can call it `quickstart` and rename it later). +1. [Clone](#clone "Clone it from github") or [download](#download "download it from github") the **QuickStart seed** into your project folder. +1. !{_Install} [!{_npm}](#install-prerequisites "What if you don't have !{_prereq}?") packages. +1. Run `!{_npm} !{_start}` to launch the sample application. + + +{@a clone} +### Clone + +Perform the _clone-to-launch_ steps with these terminal commands. + +<code-example language="sh" class="code-shell"> + git clone .git quickstart + cd quickstart + + + +</code-example> + + + +~~~ {.alert.is-important} + +`npm start` fails in _Bash for Windows_ which does not support networking to servers as of January, 2017. + + +~~~ + + + +{@a download} +### Download +<a href="!{_qsRepoZip}" title="Download the QuickStart seed repository">Download the QuickStart seed</a> +and unzip it into your project folder. Then perform the remaining steps with these terminal commands. + +<code-example language="sh" class="code-shell"> + cd quickstart + + + +</code-example> + + + +~~~ {.alert.is-important} + +`npm start` fails in _Bash for Windows_ which does not support networking to servers as of January, 2017. + + +~~~ + + + +{@a non-essential} + +## Delete _non-essential_ files (optional) + +You can quickly delete the _non-essential_ files that concern testing and QuickStart repository maintenance +(***including all git-related artifacts*** such as the `.git` folder and `.gitignore`!). + + +~~~ {.alert.is-important} + +Do this only in the beginning to avoid accidentally deleting your own tests and git setup! + + +~~~ + +Open a terminal window in the project folder and enter the following commands for your environment: + +### OS/X (bash) +<code-example language="sh" class="code-shell"> + xargs rm -rf < non-essential-files.osx.txt + rm src/app/*.spec*.ts + rm non-essential-files.osx.txt + +</code-example> + +### Windows +<code-example language="sh" class="code-shell"> + for /f %i in (non-essential-files.txt) do del %i /F /S /Q + rd .git /s /q + rd e2e /s /q + +</code-example> + + + +{@a seed} + +## What's in the QuickStart seed? +All guides and cookbooks have _at least these core files_. +Each file has a distinct purpose and evolves independently as the application grows. + +Files outside `src/` concern building, deploying, and testing your app. +They include configuration files and external dependencies. + +Files inside `src/` "belong" to your app. +Add new Typescript, HTML and CSS files inside the `src/` directory, most of them inside `src/app`, +unless told to do otherwise. + +The following are all in `src/` + +<style> + td, th {vertical-align: top} +</style> + + +<table width="100%"> + + <col width="20%"> + + </col> + + + <col width="80%"> + + </col> + + + <tr> + + <th> + File + </th> + + + <th> + Purpose + </th> + + + </tr> + + + <tr> + + <td> + <ngio-ex>app/app.component.ts</ngio-ex> + </td> + + + <td> + Defines the same `AppComponent` as the one in the QuickStart !{_playground}. + It is the **root** component of what will become a tree of nested components + as the application evolves. + </td> + + + </tr> + + + <tr if-docs="ts"> + + <td> + <code>app/app.module.ts</code> + </td> + + + <td> + Defines `AppModule`, the [root module](appmodule.html "AppModule: the root module") that tells Angular how to assemble the application. + Right now it declares only the `AppComponent`. + Soon there will be more components to declare. + </td> + + + </tr> + + + <tr> + + <td> + <ngio-ex>main.ts</ngio-ex> + </td> + + + <td> + Compiles the application with the [JIT compiler](../glossary.html#jit) and + [bootstraps](appmodule.html#main "bootstrap the application") + the application's main module (`AppModule`) to run in the browser. + The JIT compiler is a reasonable choice during the development of most projects and + it's the only viable choice for a sample running in a _live-coding_ environment like Plunker. + You'll learn about alternative compiling and [deployment](deployment.html) options later in the documentation. + + </td> + + + </tr> + + +</table> + + +### Next Step + +If you're new to Angular, we recommend staying on the [learning path](learning-angular.html "Angular learning path"). +<br></br><br></br> + +{@a install-prerequisites} + +## Appendix: !{_prereq} \ No newline at end of file diff --git a/aio/content/guide/structural-directives.md b/aio/content/guide/structural-directives.md new file mode 100644 index 0000000000..94bc390413 --- /dev/null +++ b/aio/content/guide/structural-directives.md @@ -0,0 +1,614 @@ +@title +Structural Directives + +@intro +Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements. + +@description + +<style> + h4 {font-size: 17px !important; text-transform: none !important;} + .syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; } + +</style> + +This guide looks at how Angular manipulates the DOM with **structural directives** and +how you can write your own structural directives to do the same thing. + +### Table of contents + +- [What are structural directives?](#definition) +- [*NgIf* case study](#ngIf) +- [Group sibling elements with <ng-container>](#ng-container) +- [The asterisk (\*) prefix](#asterisk) +- [Inside *NgFor*](#ngfor) + - [microsyntax](#microsyntax) + - [template input variables](#template-input-variable) + - [one structural directive per element](#one-per-element) +- [Inside the *NgSwitch* directives](#ngSwitch) +- [Prefer the (\*) prefix](#prefer-asterisk) +- [The <template> element](#template) +- [Write a structural directive](#unless) + +Try the <live-example></live-example>. + + +{@a definition} + +## What are structural directives? + +Structural directives are responsible for HTML layout. +They shape or reshape the DOM's _structure_, typically by adding, removing, or manipulating +elements. + +As with other directives, you apply a structural directive to a _host element_. +The directive then does whatever it's supposed to do with that host element and its descendents. + +Structural directives are easy to recognize. +An asterisk (\*) precedes the directive attribute name as in this example. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif'} + +No brackets. No parentheses. Just `*ngIf` set to a string. + +You'll learn in this guide that the [asterisk (\*) is a convenience notation](#asterisk) +and the string is a [_microsyntax_](#microsyntax) rather than the usual [template expression](template-syntax.html#template-expressions). +Angular "de-sugars" this notation into a marked-up `<template>` that surrounds the +host element and its descendents. +Each structural directive does something different with that template. + +Three of the common, built-in structural directives—[NgIf](template-syntax.html#ngIf), +[NgFor](template-syntax.html#ngFor), and [NgSwitch...](template-syntax.html#ngSwitch)—are +described in the [_Template Syntax_](template-syntax.html) guide and seen in samples throughout the Angular documentation. +Here's an example of them in a template: + + +{@example 'structural-directives/ts/src/app/app.component.html' region='built-in'} + +This guide won't repeat how to _use_ them. But it does explain _how they work_ +and how to [write your own](#unless) structural directive. + + +~~~ {.callout.is-helpful} + + +<header> + Directive spelling +</header> + +Throughout this guide, you'll see a directive spelled in both _UpperCamelCase_ and _lowerCamelCase_. +Already you've seen `NgIf` and `ngIf`. +There's a reason. `NgIf` refers to the directive _class_; +`ngIf` refers to the directive's _attribute name_. + +A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`). +A directive's _attribute name_ is spelled in _lowerCamelCase_ (`ngIf`). +The guide refers to the directive _class_ when talking about its properties and what the directive does. +The guide refers to the _attribute name_ when describing how +you apply the directive to an element in the HTML template. + + +~~~ + + +There are two other kinds of Angular directives, described extensively elsewhere: (1) components and (2) attribute directives. + +A *component* manages a region of HTML in the manner of a native HTML element. +Technically it's a directive with a template. + +An [*attribute* directive](attribute-directives.html) changes the appearance or behavior +of an element, component, or another directive. +For example, the built-in [`NgStyle`](template-syntax.html#ngStyle) directive +changes several element styles at the same time. + +You can apply many _attribute_ directives to one host element. +You can [only apply one](#one-per-element) _structural_ directive to a host element. + + +{@a ngIf} + +## NgIf Case Study + +`NgIf` is the simplest structural directive and the easiest to understand. +It takes a boolean value and makes an entire chunk of the DOM appear or disappear. + + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-true'} + +The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM. +Confirm that fact using browser developer tools to inspect the DOM. + +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM"> </img> +</figure> + +The top paragraph is in the DOM. The bottom, disused paragraph is not; +in its place is a comment about "template bindings" (more about that [later](#asterisk)). + +When the condition is false, `NgIf` removes its host element from the DOM, +detaches it from DOM events (the attachments that it made), +detaches the component from Angular change detection, and destroys it. +The component and DOM nodes can be garbage-collected and free up memory. + +### Why *remove* rather than *hide*? + +A directive could hide the unwanted paragraph instead by setting its `display` style to `none`. + +{@example 'structural-directives/ts/src/app/app.component.html' region='display-none'} + +While invisible, the element remains in the DOM. + +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM"> </img> +</figure> + +The difference between hiding and removing doesn't matter for a simple paragraph. +It does matter when the host element is attached to a resource intensive component. +Such a component's behavior continues even when hidden. +The component stays attached to its DOM element. It keeps listening to events. +Angular keeps checking for changes that could affect data bindings. +Whatever the component was doing, it keeps doing. + +Although invisible, the component—and all of its descendant components—tie up resources. +The performance and memory burden can be substantial, responsiveness can degrade, and the user sees nothing. + +On the positive side, showing the element again is quick. +The component's previous state is preserved and ready to display. +The component doesn't re-initialize—an operation that could be expensive. +So hiding and showing is sometimes the right thing to do. + +But in the absence of a compelling reason to keep them around, +your preference should be to remove DOM elements that the user can't see +and recover the unused resources with a structural directive like `NgIf` . + +**These same considerations apply to every structural directive, whether built-in or custom.** +Before applying a structural directive, you might want to pause for a moment +to consider the consequences of adding and removing elements and of creating and destroying components. + + +{@a ngcontainer} + + +{@a ng-container} + +## Group sibling elements with <ng-container> + +There's often a _root_ element that can and should host the structural directive. +The list element (`<li>`) is a typical host element of an `NgFor` repeater. + + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngfor-li'} + +When there isn't a host element, you can usually wrap the content in a native HTML container element, +such as a `<div>`, and attach the directive to that wrapper. + + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif'} + +Introducing another container element—typically a `<span>` or `<div>`—to +group the elements under a single _root_ is usually harmless. +_Usually_ ... but not _always_. + +The grouping element may break the template appearance because CSS styles +neither expect nor accommodate the new layout. +For example, suppose you have the following paragraph layout. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-span'} + +You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph. + +{@example 'structural-directives/ts/src/app/app.component.css' region='p-span'} + +The constructed paragraph renders strangely. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style"> </img> +</figure> + +The `p span` style, intended for use elsewhere, was inadvertently applied here. + +Another problem: some HTML elements require all immediate children to be of a specific type. +For example, the `<select>` tag requires `<option>` children. +You can't wrap the _options_ in a conditional `<div>` or a `<span>`. + +When you try this, + +{@example 'structural-directives/ts/src/app/app.component.html' region='select-span'} + +the drop down is empty. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/bad-select.png' alt="spanned options don't work"> </img> +</figure> + +The browser won't display an `<option>` within a `<span>`. + +### <ng-container> to the rescue + +The Angular `<ng-container>` is a grouping element that doesn't interfere with styles or layout +because Angular _doesn't put it in the DOM_. + +Here's the conditional paragraph again, this time using `<ng-container>`. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-ngcontainer'} + +It renders properly. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style"> </img> +</figure> + +Now conditionally exclude a _select_ `<option>` with `<ng-container>`. + +{@example 'structural-directives/ts/src/app/app.component.html' region='select-ngcontainer'} + +The drop down works properly. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly"> </img> +</figure> + +The `<ng-container>` is a syntax element recognized by the Angular parser. +It's not a directive, component, class, or interface. +It's more like the curly braces in a JavaScript `if`-block: + +<code-example language="javascript"> + if (someCondition) { + statement1; + statement2; + statement3; + } +</code-example> + +Without those braces JavaScript could only execute the first statement +when you intend to conditionally execute all of them as a single block. +The `<ng-container>` satisfies a similar need in Angular templates. + + +{@a asterisk} + +## The asterisk (\*) prefix + +Surely you noticed the asterisk (\*) prefix to the directive name +and wondered why it is necessary and what it does. + +Here is `*ngIf` displaying the hero's name if `hero` exists. + + +{@example 'structural-directives/ts/src/app/app.component.html' region='asterisk'} + +The asterisk is "syntactic sugar" for something a bit more complicated. +Internally, Angular "de-sugars" it in two stages. +First, it translates the `*ngIf="..."` into a template _attribute_, `template="ngIf ..."`,  like this. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-template-attr'} + +Then it translates the template _attribute_ into a template _element_, wrapped around the host element, like this. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngif-template'} + +* The `*ngIf` directive moved to the `<template>` tag where it became a property binding,`[ngIf]`. +* The rest of the `<div>`, including its class attribute, moved inside the `<template>` tag. + +None of these forms are actually rendered. +Only the finished product ends up in the DOM. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM"> </img> +</figure> + +Angular consumed the `<template>` content during its actual rendering and +replaced the `<template>` with a diagnostic comment. + +The [`NgFor`](#ngfor) and [`NgSwitch...`](#ngswitch) directives follow the same pattern. + + +{@a ngfor} + +## Inside _*ngFor_ + +Angular transforms the `*ngFor` in similar fashion from asterisk (\*) syntax through +template _attribute_ to template _element_. + +Here's a full-featured application of `NgFor`, written all three ways: + +{@example 'structural-directives/ts/src/app/app.component.html' region='inside-ngfor'} + +This is manifestly more complicated than `ngIf` and rightly so. +The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide. +At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`). + +You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](microsyntax). + + +~~~ {.alert.is-helpful} + +Everything _outside_ the `ngFor` string stays with the host element +(the `<div>`) as it moves inside the `<template>`. +In this example, the `[ngClass]="odd"` stays on the `<div>`. + + +~~~ + + + +{@a microsyntax} +### microsyntax +The Angular microsyntax lets you configure a directive in a compact, friendly string. +The microsyntax parser translates that string into attributes on the `<template>`: + +* The `let` keyword declares a [_template input variable_](#template-input-variable) +that you reference within the template. The input variables in this example are `hero`, `i`, and `odd`. +The parser translates `let hero`, `let i`, and `let odd` into variables named, +`let-hero`, `let-i`, and `let-odd`. + +* The microsyntax parser takes `of` and `trackby`, title-cases them (`of` -> `Of`, `trackBy` -> `TrackBy`), +and prefixes them with the directive's attribute name (`ngFor`), yielding the names `ngForOf` and `ngForTrackBy`. +Those are the names of two `NgFor` _input properties_ . +That's how the directive learns that the list is `heroes` and the track-by function is `trackById`. + +* As the `NgFor` directive loops through the list, it sets and resets properties of its own _context_ object. +These properties include `index` and `odd` and a special property named `$implicit`. + +* The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`. +Angular sets them to the current value of the context's `index` and `odd` properties. + +* The context property for `let-hero` wasn't specified. +It's intended source is implicit. +Angular sets `let-hero` to the value of the context's `$implicit` property +which `NgFor` has initialized with the hero for the current iteration. + +* The [API guide](../api/common/index/NgFor-directive.html "API: NgFor") +describes additional `NgFor` directive properties and context properties. + +These microsyntax mechanisms are available to you when you write your own structural directives. +Studying the source code for `NgIf` and `NgFor` is a great way to learn more. + + + +{@a template-input-variable} + + +{@a template-input-variables} +### Template input variable + +A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template. +There are several such variables in this example: `hero`, `li`, and `odd`. +All are preceded by the keyword `let`. + +A _template input variable_ is **_not_** the same as a +[template _reference_ variable](template-syntax.html#ref-vars), +neither _semantically_ nor _syntactically_. + +You declare a template _input_ variable declaration with the `let` keyword (`let hero`). +The variable's scope is limited to a _single instance_ of the repeated template. +You can use the same variable name again in the definition of other structural directives. + +You declare a template _reference_ variable declaration by prefixing the variable name with `#` (`#var`). +A _reference_ variable refers to its attached element, component or directive. +It can be accessed _anywhere_ in the _entire template_. + +Template _input_ and _reference_ variable names have their own namespaces. The `hero` in `let hero` is never the same +variable as the `hero` declared as `#hero`. + + +{@a one-per-element} +### One structural directive per host element + +Someday you'll want to to repeat a block of HTML but only when a particular condition is true. +You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element. +Angular won't let you. You may apply only one _structural_ directive to an element. + +The reason is simplicity. Structural directives can do complex things with the host element and its descendents. +When two directives lay claim to the same host element, which one takes precedence? +Which should go first, the `NgIf` or the `NgFor`? Can the `NgIf` cancel the effect of the `NgFor`? +If so (and it seems like it should be so), how should Angular generalize the ability to cancel for other structural directives? + +There are no easy answers to these questions. Prohibiting multiple structural directives makes them moot. +There's an easy solution for this use case: put the `*ngIf` on a container element that wraps the `*ngFor` element. +One or both elements can be an [`ng-container`](#ngcontainer) so you don't have to introduce extra levels of HTML. + + +{@a ngswitch} + +## Inside the _NgSwitch_ directives + +The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault`. + +Here's an example. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch'} + +The switch value assigned to `NgSwitch` (`hero.emotion`) determines which +(if any) of the switch cases are displayed. + +`NgSwitch` itself is not a structural directive. +It's an _attribute_ directive that controls the behavior of the other two switch directives. +That's why you write `[ngSwitch]`, never `*ngSwitch`. + +`NgSwitchCase` and `NgSwitchDefault` _are_ structural directives. +You attach them to elements using the asterisk (\*) prefix notation. +An `NgSwitchCase` displays its host element when its value matches the switch value. +The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value. + +The element to which you apply a directive is its _host_ element. +The `<happy-hero>` is the host element for the happy `*ngSwitchCase`. +The `<unknown-hero>` is the host element for the `*ngSwitchDefault`. +As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault` +can be "de-sugared" into the template _attribute_ form. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch-template-attr'} + +That, in turn, can be "de-sugared" into the `<template>` element form. + +{@example 'structural-directives/ts/src/app/app.component.html' region='ngswitch-template'} + + + +{@a prefer-asterisk} +## Prefer the asterisk (\*) syntax. + +The asterisk (\*) syntax is more clear than the other "de-sugared" forms. +Use [<ng-container>](#ng-container) when there's no single element +to host the directive. + +While there's rarely a good reason to apply a structural directive in template _attribute_ or _element_ form, +it's still important to know that Angular creates a `<template>` and to understand how it works. +You'll refer to the `<template>` when you [write your own structural directive](#unless). + + +{@a template} + +## The *<template>* + +The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template" target="_blank" title="MDN: Template Tag">HTML 5 <template></a> +is a formula for rendering HTML. +It is never displayed directly. +In fact, before rendering the view, Angular _replaces_ the `<template>` and its contents with a comment. + +If there is no structural directive, if you merely wrap some elements in a `<template>` and do nothing with it, +those elements disappear. +That's the fate of the middle "hip" in the phrase "Hip! Hip! Hooray!". + +{@example 'structural-directives/ts/src/app/app.component.html' region='template-tag'} + +Angular erases the middle "hip", leaving the cheer a bit less enthusiastic. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/template-rendering.png' width="350" alt="template tag rendering"> </img> +</figure> + +A structural directive puts a `<template>` to work +as you'll see when you write your own structural directive. + + +{@a unless} + +## Write a structural directive +In this section, you write a `UnlessDirective` structural directive +that does the opposite of `NgIf`. +`NgIf` displays the template content when the condition is `true`. +`UnlessDirective` displays the content when the condition is ***false***. + + +{@example 'structural-directives/ts/src/app/app.component.html' region='myUnless-1'} + + + +{@example 'structural-directives/ts/src/app/unless.directive.ts' region='skeleton'} + +The directive's _selector_ is typically the directive's **attribute name** in square brackets.`[myUnless]`. +The brackets define a CSS +<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" target="_blank" title="MDN: Attribute selectors">attribute selector</a>. + +The directive _attribute name_ should be spelled in _lowerCamelCase_ and begin with a prefix. +Don't use `ng`. That prefix belongs to Angular. +Pick something short that fits you or your company. +In this example, the prefix is `my`. +The directive _class_ name ends in `Directive` per the [style guide](style-guide.html#02-03 "Angular Style Guide"). +Angular's own directives do not. + +### _TemplateRef_ and _ViewContainerRef_ + +A simple structural directive like this one creates an +[_embedded view_](../api/core/index/EmbeddedViewRef-class.html "API: EmbeddedViewRef") +from the Angular-generated `<template>` and inserts that view in a +[_view container_](../api/core/index/ViewContainerRef-class.html "API: ViewContainerRef") +adjacent to the directive's original `<p>` host element. + +You'll acquire the `<template>` contents with a +[`TemplateRef`](../api/core/index/TemplateRef-class.html "API: TemplateRef") +and access the _view container_ through a +[`ViewContainerRef`](../api/core/index/ViewContainerRef-class.html "API: ViewContainerRef"). + +You inject both in the directive constructor as private variables of the class. + + +{@example 'structural-directives/ts/src/app/unless.directive.ts' region='ctor'} + +### The _myUnless_ property + +The directive consumer expects to bind a true/false condition to `[myUnless]`. +That means the directive needs a `myUnless` property, decorated with `@Input` +Read about `@Input` in the [_Template Syntax_](template-syntax.html#inputs-outputs) guide. + + +{@example 'structural-directives/ts/src/app/unless.directive.ts' region='set'} + +Angular sets the `myUnless` property whenever the value of the condition changes. +Because the `myUnless` property does work, it needs a setter. + +* If the condition is falsy and the view hasn't been created previously, +tell the _view container_ to create the _embedded view_ from the template. + +* If the condition is truthy and the view is currently displayed, +clear the container which also destroys the view. + +Nobody reads the `myUnless` property so it doesn't need a getter. + +The completed directive code looks like this: + + +{@example 'structural-directives/ts/src/app/unless.directive.ts' region='no-docs'} + +Add this directive to the `!{_declsVsDirectives}` !{_array} of the !{_AppModuleVsAppComp}. + +Then create some HTML to try it. + +{@example 'structural-directives/ts/src/app/app.component.html' region='myUnless'} + +When the `condition` is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears. +When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears. +<figure class='image-display'> + <img src='/resources/images/devguide/structural-directives/unless-anim.gif' alt="UnlessDirective in action"> </img> +</figure> + + + +{@a summary} + +## Summary +You can both try and download the source code for this guide in the <live-example></live-example>. + +Here is the source from the `app/` folder. + +<md-tab-group> + + <md-tab label="app.component.ts"> + {@example 'structural-directives/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="app.component.html"> + {@example 'structural-directives/ts/src/app/app.component.html'} + </md-tab> + + + <md-tab label="app.component.css"> + {@example 'structural-directives/ts/src/app/app.component.css'} + </md-tab> + + + <md-tab label="app.module.ts"> + {@example 'structural-directives/ts/src/app/app.module.ts'} + </md-tab> + + + <md-tab label="hero.ts"> + {@example 'structural-directives/ts/src/app/hero.ts'} + </md-tab> + + + <md-tab label="hero-switch.components.ts"> + {@example 'structural-directives/ts/src/app/hero-switch.components.ts'} + </md-tab> + + + <md-tab label="unless.directive.ts"> + {@example 'structural-directives/ts/src/app/unless.directive.ts'} + </md-tab> + + +</md-tab-group> + +You learned +* that structural directives manipulate HTML layout. +* to use [`<ng-container>`](#ngcontainer) as a grouping element when there is no suitable host element. +* that the angular "de-sugars" [asterisk (\*) syntax](#asterisk) into a `<template>`. +* how that works for the `NgIf`, `NgFor` and `NgSwitch` built-in directives. +* about the [_microsyntax_](#microsyntax) that expands into a [`<template>`](#template). +* to write a [custom structural directive](#unless), `UnlessDirective`. \ No newline at end of file diff --git a/aio/content/guide/style-guide.md b/aio/content/guide/style-guide.md new file mode 100644 index 0000000000..5d78918407 --- /dev/null +++ b/aio/content/guide/style-guide.md @@ -0,0 +1,3649 @@ +@title +Style Guide + +@intro +Write Angular with style. + +@description +Welcome to the Angular Style Guide + +## Purpose + +Looking for an opinionated guide to Angular syntax, conventions, and application structure? +Step right in! +This style guide presents our preferred conventions and, as importantly, explains why. +## Style vocabulary + +Each guideline describes either a good or bad practice, and all have a consistent presentation. + +The wording of each guideline indicates how strong the recommendation is. + + +~~~ {.s-rule.do} + +**Do** is one that should always be followed. +_Always_ might be a bit too strong of a word. +Guidelines that literally should always be followed are extremely rare. +On the other hand, you need a really unusual case for breaking a *Do* guideline. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** guidelines should generally be followed. +If you fully understand the meaning behind the guideline and have a good reason to deviate, then do so. Please strive to be consistent. + + +~~~ + + + +~~~ {.s-rule.avoid} + +**Avoid** indicates something you should almost never do. Code examples to *avoid* have an unmistakeable red header. + +~~~ + + +## File structure conventions + +Some code examples display a file that has one or more similarly named companion files. +For example, `hero.component.ts` and `hero.component.html`. + +The guideline will use the shortcut `hero.component.ts|html|css|spec` to represent those various files. Using this shortcut makes this guide's file structures easier to read and more terse. + + + +{@a toc} +## Table of contents + + 1. [Single responsibility](#single-responsibility) + 1. [Naming](#naming) + 1. [Coding conventions](#coding-conventions) + 1. [App structure and Angular modules](#application-structure-and-angular-modules) + 1. [Components](#components) + 1. [Directives](#directives) + 1. [Services](#services) + 1. [Data services](#data-services) + 1. [Lifecycle hooks](#lifecycle-hooks) + 1. [Appendix](#appendix) + +## Single responsibility + +Apply the +<a href="https://wikipedia.org/wiki/Single_responsibility_principle" target="_blank"><i>Single Responsibility Principle</i> (SPR)</a> +to all components, services, and other symbols. +This helps make the app cleaner, easier to read and maintain, and more testable. + +### <a id="01-01"></a>_Rule of One_ +#### <a href="#01-01">Style 01-01</a> + +~~~ {.s-rule.do} + +**Do** define one thing, such as a service or component, per file. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** limiting files to 400 lines of code. + + +~~~ + + +<div class='s-why'> + **Why?** One component per file makes it far easier to read, maintain, and avoid + collisions with teams in source control. + +</div> + + +<div class='s-why'> + **Why?** One component per file avoids hidden bugs that often arise when combining components in a file where they may share variables, create unwanted closures, or unwanted coupling with dependencies. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** A single component can be the default export for its file which facilitates lazy loading with the router. +</div> + +The key is to make the code more reusable, easier to read, and less mistake prone. + +The following *negative* example defines the `AppComponent`, bootstraps the app, defines the `Hero` model object, and loads heroes from the server ... all in the same file. *Don't do this*. + + +{@example 'style-guide/ts/src/01-01/app/heroes/hero.component.avoid.ts'} + +It is a better practice to redistribute the component and its +supporting classes into their own, dedicated files. + +<md-tab-group> + + <md-tab label="main.ts"> + {@example 'style-guide/ts/src/01-01/main.ts'} + </md-tab> + + + <md-tab label="app/app.module.ts"> + {@example 'style-guide/ts/src/01-01/app/app.module.ts'} + </md-tab> + + + <md-tab label="app/app.component.ts"> + {@example 'style-guide/ts/src/01-01/app/app.component.ts'} + </md-tab> + + + <md-tab label="app/heroes/heroes.component.ts"> + {@example 'style-guide/ts/src/01-01/app/heroes/heroes.component.ts'} + </md-tab> + + + <md-tab label="app/heroes/shared/hero.service.ts"> + {@example 'style-guide/ts/src/01-01/app/heroes/shared/hero.service.ts'} + </md-tab> + + + <md-tab label="app/heroes/shared/hero.model.ts"> + {@example 'style-guide/ts/src/01-01/app/heroes/shared/hero.model.ts'} + </md-tab> + + + <md-tab label="app/heroes/shared/mock-heroes.ts"> + {@example 'style-guide/ts/src/01-01/app/heroes/shared/mock-heroes.ts'} + </md-tab> + + +</md-tab-group> + +As the app grows, this rule becomes even more important. +<a href="#toc">Back to top</a> +### <a id="01-02"></a>Small functions +#### <a href="#01-02">Style 01-02</a> + +~~~ {.s-rule.do} + +**Do** define small functions + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** limiting to no more than 75 lines. + + +~~~ + + +<div class='s-why'> + **Why?** Small functions are easier to test, especially when they do one thing and serve one purpose. + +</div> + + +<div class='s-why'> + **Why?** Small functions promote reuse. + +</div> + + +<div class='s-why'> + **Why?** Small functions are easier to read. + +</div> + + +<div class='s-why'> + **Why?** Small functions are easier to maintain. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Small functions help avoid hidden bugs that come with large functions that share variables with external scope, create unwanted closures, or unwanted coupling with dependencies. + +</div> + +<a href="#toc">Back to top</a> +## Naming + +Naming conventions are hugely important to maintainability and readability. This guide recommends naming conventions for the file name and the symbol name. + +### <a id="02-01"></a>General Naming Guidelines +#### <a href="#02-01">Style 02-01</a> + + +~~~ {.s-rule.do} + +**Do** use consistent names for all symbols. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** follow a pattern that describes the symbol's feature then its type. The recommended pattern is `feature.type.ts`. + + +~~~ + + +<div class='s-why'> + **Why?** Naming conventions help provide a consistent way to find content at a glance. Consistency within the project is vital. Consistency with a team is important. Consistency across a company provides tremendous efficiency. + +</div> + + +<div class='s-why'> + **Why?** The naming conventions should simply help find desited code faster and make it easier to understand. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Names of folders and files should clearly convey their intent. For example, `app/heroes/hero-list.component.ts` may contain a component that manages a list of heroes. + +</div> + +<a href="#toc">Back to top</a> +### <a id="02-02"></a>Separate file names with dots and dashes +#### <a href="#02-02">Style 02-02</a> + + +~~~ {.s-rule.do} + +**Do** use dashes to separate words in the descriptive name. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use dots to separate the descriptive name from the type. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use consistent type names for all components following a pattern that describes the component's feature then its type. A recommended pattern is `feature.type.ts`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use conventional type names including `.service`, `.component`, `.pipe`, `.module`, and `.directive`. +Invent additional type names if you must but take care not to create too many. + + +~~~ + + +<div class='s-why'> + **Why?** Type names provide a consistent way to quickly identify what is in the file. + +</div> + + +<div class='s-why'> + **Why?** Type names make it easy to find a specific file type using an editor or IDE's fuzzy search techniques. + +</div> + + +<div class='s-why'> + **Why?** Unabbreviated type names such as `.service` are descriptive and unambiguous. + Abbreviations such as `.srv`, `.svc`, and `.serv` can be confusing. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Type names provide pattern matching for any automated tasks. + +</div> + +<a href="#toc">Back to top</a> +### <a id="02-03"></a>Symbols and file names +#### <a href="#02-03">Style 02-03</a> + + +~~~ {.s-rule.do} + +**Do** use consistent names for all assets named after what they represent. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use upper camel case for class names. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** match the name of the symbol to the name of the file. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** append the symbol name with the conventional suffix (such as `Component`, +`Directive`, `Module`, `Pipe`, or `Service`) for a thing of that type. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** give the filename the conventional suffix (such as `.component.ts`, `.directive.ts`, +`.module.ts`, `.pipe.ts`, or `.service.ts`) for a file of that type. + +~~~ + + +<div class='s-why'> + **Why?** Consistent conventions make it easy to quickly identify + and reference assets of different types. + +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Component({ ... }) + export class AppComponent { } + </code-example> + + + </td> + + + <td> + app.component.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Component({ ... }) + export class HeroesComponent { } + </code-example> + + + </td> + + + <td> + heroes.component.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Component({ ... }) + export class HeroListComponent { } + </code-example> + + + </td> + + + <td> + hero-list.component.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Component({ ... }) + export class HeroDetailComponent { } + </code-example> + + + </td> + + + <td> + hero-detail.component.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Directive({ ... }) + export class ValidationDirective { } + </code-example> + + + </td> + + + <td> + validation.directive.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class AppModule + </code-example> + + + </td> + + + <td> + app.module.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Pipe({ name: 'initCaps' }) + export class InitCapsPipe implements PipeTransform { } + </code-example> + + + </td> + + + <td> + init-caps.pipe.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Injectable() + export class UserProfileService { } + </code-example> + + + </td> + + + <td> + user-profile.service.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +### <a id="02-04"></a>Service names +#### <a href="#02-04">Style 02-04</a> + + +~~~ {.s-rule.do} + +**Do** use consistent names for all services named after their feature. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** suffix a service class name with Service. +For example, something that gets data or heroes +should be called a `DataService` or a `HeroService`. + +A few terms are unambiguously services. They typically +indicate agency by ending in "er". You may prefer to name +a service that logs messages `Logger` rather than `LoggerService`. +Decide if this exception is agreeable in your project. +As always, strive for consistency. + + +~~~ + + +<div class='s-why'> + **Why?** Provides a consistent way to quickly identify and reference services. + +</div> + + +<div class='s-why'> + **Why?** Clear service names such as `Logger` do not require a suffix. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Service names such as `Credit` are nouns and require a suffix and should be named with a suffix when it is not obvious if it is a service or something else. + +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Injectable() + export class HeroDataService { } + </code-example> + + + </td> + + + <td> + hero-data.service.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Injectable() + export class CreditService { } + </code-example> + + + </td> + + + <td> + credit.service.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Injectable() + export class Logger { } + </code-example> + + + </td> + + + <td> + logger.service.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +### <a id="02-05"></a>Bootstrapping +#### <a href="#02-05">Style 02-05</a> + + +~~~ {.s-rule.do} + +**Do** put bootstrapping and platform logic for the app in a file named `main.ts`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** include error handling in the bootstrapping logic. + + +~~~ + + + +~~~ {.s-rule.avoid} + +**Avoid** putting app logic in the `main.ts`. Instead, consider placing it in a component or service. + + +~~~ + + +<div class='s-why'> + **Why?** Follows a consistent convention for the startup logic of an app. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Follows a familiar convention from other technology platforms. + +</div> + + + +{@example 'style-guide/ts/src/02-05/main.ts'} + +<a href="#toc">Back to top</a> +### <a id="02-06"></a>Directive selectors +#### <a href="#02-06">Style 02-06</a> + + +~~~ {.s-rule.do} + +**Do** Use lower camel case for naming the selectors of directives. + + +~~~ + + +<div class='s-why'> + **Why?** Keeps the names of the properties defined in the directives that are bound to the view consistent with the attribute names. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** The Angular HTML parser is case sensitive and will recognize lower camel case. + +</div> + +<a href="#toc">Back to top</a> +### <a id="02-07"></a>Custom prefix for components +#### <a href="#02-07">Style 02-07</a> + + +~~~ {.s-rule.do} + +**Do** use a hyphenated, lowercase element selector value (e.g. `admin-users`). + + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use a custom prefix for a component selector. +For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the prefix `admin` represents an admin feature area. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** use a prefix that identifies the feature area or the app itself. + + +~~~ + + +<div class='s-why'> + **Why?** Prevents element name collisions with components in other apps and with native HTML elements. + +</div> + + +<div class='s-why'> + **Why?** Makes it easier to promote and share the component in other apps. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Components are easy to identify in the DOM. + +</div> + + + +{@example 'style-guide/ts/src/02-07/app/heroes/hero.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/02-07/app/users/users.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/02-07/app/heroes/hero.component.ts' region='example'} + + + +{@example 'style-guide/ts/src/02-07/app/users/users.component.ts' region='example'} + +### <a id="02-08"></a>Custom prefix for directives +#### <a href="#02-08">Style 02-08</a> + + +~~~ {.s-rule.do} + +**Do** use a custom prefix for the selector of directives (e.g, the prefix `toh` from **T**our **o**f **H**eroes). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** spell non-element selectors in lower camel case unless the selector is meant to match a native HTML attribute. + + +~~~ + + +<div class='s-why'> + **Why?** Prevents name collisions. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Directives are easily identified. + +</div> + + + +{@example 'style-guide/ts/src/02-08/app/shared/validate.directive.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/02-08/app/shared/validate.directive.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="02-09"></a>Pipe names +#### <a href="#02-09">Style 02-09</a> + + +~~~ {.s-rule.do} + +**Do** use consistent names for all pipes, named after their feature. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Provides a consistent way to quickly identify and reference pipes. + +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Pipe({ name: 'ellipsis' }) + export class EllipsisPipe implements PipeTransform { } + </code-example> + + + </td> + + + <td> + ellipsis.pipe.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @Pipe({ name: 'initCaps' }) + export class InitCapsPipe implements PipeTransform { } + </code-example> + + + </td> + + + <td> + init-caps.pipe.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +### <a id="02-10"></a>Unit test file names +#### <a href="#02-10">Style 02-10</a> + + +~~~ {.s-rule.do} + +**Do** name test specification files the same as the component they test. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name test specification files with a suffix of `.spec`. + + +~~~ + + +<div class='s-why'> + **Why?** Provides a consistent way to quickly identify tests. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Provides pattern matching for [karma](http://karma-runner.github.io/) or other test runners. + +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + Components + </td> + + + <td> + heroes.component.spec.ts hero-list.component.spec.ts hero-detail.component.spec.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + Services + </td> + + + <td> + logger.service.spec.ts hero.service.spec.ts filter-text.service.spec.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + Pipes + </td> + + + <td> + ellipsis.pipe.spec.ts init-caps.pipe.spec.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +### <a id="02-11"></a>_End-to-End_ (E2E) test file names +#### <a href="#02-11">Style 02-11</a> + + +~~~ {.s-rule.do} + +**Do** name end-to-end test specification files after the feature they test with a suffix of `.e2e-spec`. + + +~~~ + + +<div class='s-why'> + **Why?** Provides a consistent way to quickly identify end-to-end tests. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Provides pattern matching for test runners and build automation. + +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + End to End Tests + </td> + + + <td> + app.e2e-spec.ts heroes.e2e-spec.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +### <a id="02-12"></a>Angular _NgModule_ names +#### <a href="#02-12">Style 02-12</a> + + +~~~ {.s-rule.do} + +**Do** append the symbol name with the suffix `Module`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** give the file name the `.module.ts` extension. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name the module after the feature and folder it resides in. + + +~~~ + + +<div class='s-why'> + **Why?** Provides a consistent way to quickly identify and reference modules. + +</div> + + +<div class='s-why'> + **Why?** Upper camel case is conventional for identifying objects that can be instantiated using a constructor. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Easily identifies the module as the root of the same named feature. + +</div> + + + +~~~ {.s-rule.do} + +**Do** suffix a _RoutingModule_ class name with `RoutingModule`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** end the filename of a _RoutingModule_ with `-routing.module.ts`. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** A `RoutingModule` is a module dedicated exclusively to configuring the Angular router. + A consistent class and file name convention make these modules easy to spot and verify. +</div> + + +<table width="100%"> + + <col width="50%"> + + </col> + + + <col width="50%"> + + </col> + + + <tr> + + <th> + Symbol Name + </th> + + + <th> + File Name + </th> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class AppModule { } + </code-example> + + + </td> + + + <td> + app.module.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class HeroesModule { } + </code-example> + + + </td> + + + <td> + heroes.module.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class VillainsModule { } + </code-example> + + + </td> + + + <td> + villains.module.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class AppRoutingModule { } + </code-example> + + + </td> + + + <td> + app-routing.module.ts + </td> + + + </tr> + + + <tr style=top> + + <td> + + <code-example> + @NgModule({ ... }) + export class HeroesRoutingModule { } + </code-example> + + + </td> + + + <td> + heroes-routing.module.ts + </td> + + + </tr> + + +</table> + +<a href="#toc">Back to top</a> +## Coding conventions + +Have consistent set of coding, naming, and whitespace conventions. + +### <a id="03-01"></a>Classes +#### <a href="#03-01">Style 03-01</a> + + +~~~ {.s-rule.do} + +**Do** use upper camel case when naming classes. + + +~~~ + + +<div class='s-why'> + **Why?** Follows conventional thinking for class names. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Classes can be instantiated and construct an instance. + By convention, upper camel case indicates a constructable asset. + +</div> + + + +{@example 'style-guide/ts/src/03-01/app/core/exception.service.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/03-01/app/core/exception.service.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="03-02"></a>Constants +#### <a href="#03-02">Style 03-02</a> + + +~~~ {.s-rule.do} + +**Do** declare variables with `const` if their values should not change during the application lifetime. + + +~~~ + + +<div class='s-why'> + **Why?** Conveys to readers that the value is invariant. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** TypeScript helps enforce that intent by requiring immediate initialization and by + preventing subsequent re-assignment. + +</div> + + + +~~~ {.s-rule.consider} + +**Consider** spelling `const` variables in lower camel case. + + +~~~ + + +<div class='s-why'> + **Why?** Lower camel case variable names (`heroRoutes`) are easier to read and understand + than the traditional UPPER_SNAKE_CASE names (`HERO_ROUTES`). + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** The tradition of naming constants in UPPER_SNAKE_CASE reflects + an era before the modern IDEs that quickly reveal the `const` declaration. + TypeScript itself prevents accidental reassignment. + +</div> + + + +~~~ {.s-rule.do} + +**Do** tolerate _existing_ `const` variables that are spelled in UPPER_SNAKE_CASE. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** The tradition of UPPER_SNAKE_CASE remains popular and pervasive, + especially in third party modules. + It is rarely worth the effort to change them at the risk of breaking existing code and documentation. + +</div> + + + +{@example 'style-guide/ts/src/03-02/app/core/data.service.ts'} + +<a href="#toc">Back to top</a> +### <a id="03-03"></a>Interfaces +#### <a href="#03-03">Style 03-03</a> + + +~~~ {.s-rule.do} + +**Do** name an interface using upper camel case. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** naming an interface without an `I` prefix. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** using a class instead of an interface. + + +~~~ + + +<div class='s-why'> + **Why?** <a href="https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines" target="_blank">TypeScript guidelines</a> + discourage the `I` prefix. + +</div> + + +<div class='s-why'> + **Why?** A class alone is less code than a _class-plus-interface_. + +</div> + + +<div class='s-why'> + **Why?** A class can act as an interface (use `implements` instead of `extends`). + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** An interface-class can be a provider lookup token in Angular dependency injection. + +</div> + + + +{@example 'style-guide/ts/src/03-03/app/core/hero-collector.service.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/03-03/app/core/hero-collector.service.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="03-04"></a>Properties and methods +#### <a href="#03-04">Style 03-04</a> + + +~~~ {.s-rule.do} + +**Do** use lower camel case to name properties and methods. + + +~~~ + + + +~~~ {.s-rule.avoid} + +**Avoid** prefixing private properties and methods with an underscore. + + +~~~ + + +<div class='s-why'> + **Why?** Follows conventional thinking for properties and methods. + +</div> + + +<div class='s-why'> + **Why?** JavaScript lacks a true private property or method. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** TypeScript tooling makes it easy to identify private vs public properties and methods. + +</div> + + + +{@example 'style-guide/ts/src/03-04/app/core/toast.service.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/03-04/app/core/toast.service.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="03-06"></a>Import line spacing +#### <a href="#03-06">Style 03-06</a> + + +~~~ {.s-rule.consider} + +**Consider** leaving one empty line between third party imports and application imports. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** listing import lines alphabetized by the module. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** listing destructured imported symbols alphabetically. + + +~~~ + + +<div class='s-why'> + **Why?** The empty line separates _your_ stuff from _their_ stuff. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Alphabetizing makes it easier to read and locate symbols. + +</div> + + + +{@example 'style-guide/ts/src/03-06/app/heroes/shared/hero.service.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/03-06/app/heroes/shared/hero.service.ts' region='example'} + +<a href="#toc">Back to top</a> +## Application structure and Angular modules + +Have a near-term view of implementation and a long-term vision. Start small but keep in mind where the app is heading down the road. + +All of the app's code goes in a folder named `src`. +All feature areas are in their own folder, with their own Angular module. + +All content is one asset per file. Each component, service, and pipe is in its own file. +All third party vendor scripts are stored in another folder and not in the `src` folder. +You didn't write them and you don't want them cluttering `src`. +Use the naming conventions for files in this guide. +<a href="#toc">Back to top</a> +### <a id="04-01"></a>_LIFT_ +#### <a href="#04-01">Style 04-01</a> + + +~~~ {.s-rule.do} + +**Do** structure the app such that you can `L`ocate code quickly, +`I`dentify the code at a glance, +keep the `F`lattest structure you can, and +`T`ry to be DRY. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** define the structure to follow these four basic guidelines, listed in order of importance. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** LIFT Provides a consistent structure that scales well, is modular, and makes it easier to increase developer efficiency by finding code quickly. + To confirm your intuition about a particular structure, ask: + _can I quickly open and start work in all of the related files for this feature_? + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-02"></a>Locate +#### <a href="#04-02">Style 04-02</a> + + +~~~ {.s-rule.do} + +**Do** make locating code intuitive, simple and fast. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** + To work efficiently you must be able to find files quickly, + especially when you do not know (or do not remember) the file _names_. + Keeping related files near each other in an intuitive location saves time. + A descriptive folder structure makes a world of difference to you and the people who come after you. + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-03"></a>Identify +#### <a href="#04-03">Style 04-03</a> + + +~~~ {.s-rule.do} + +**Do** name the file such that you instantly know what it contains and represents. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** be descriptive with file names and keep the contents of the file to exactly one component. + + +~~~ + + + +~~~ {.s-rule.avoid} + +**Avoid** files with multiple components, multiple services, or a mixture. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Spend less time hunting and pecking for code, and become more efficient. + Longer file names are far better than _short-but-obscure_ abbreviated names. + +</div> + + +It may be advantageous to deviate from the _one-thing-per-file_ rule when +you have a set of small, closely-related features that are better discovered and understood +in a single file than as multiple files. Be wary of this loophole. +<a href="#toc">Back to top</a> +### <a id="04-04"></a>Flat +#### <a href="#04-04">Style 04-04</a> + + +~~~ {.s-rule.do} + +**Do** keep a flat folder structure as long as possible. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** creating sub-folders when a folder reaches seven or more files. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** configuring the IDE to hide distracting, irrelevant files such as generated `.js` and `.js.map` files. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** No one wants to search for a file through seven levels of folders. + A flat structure is easy to scan. + + On the other hand, + <a href="https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two" target="_blank">psychologists believe</a> + that humans start to struggle when the number of adjacent interesting things exceeds nine. + So when a folder has ten or more files, it may be time to create subfolders. + + Base your decision on your comfort level. + Use a flatter structure until there is an obvious value to creating a new folder. + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-05"></a>_T-DRY_ (Try to be _DRY_) +#### <a href="#04-05">Style 04-05</a> + + +~~~ {.s-rule.do} + +**Do** be DRY (Don't Repeat Yourself) + + +~~~ + + + +~~~ {.s-rule.avoid} + +**Avoid** being so DRY that you sacrifice readability. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Being DRY is important, but not crucial if it sacrifices the other elements of LIFT. + That's why it's called _T-DRY_. + For example, it's redundant to name a component, `hero-view.component.html` because a component is obviously a view. + But if something is not obvious or departs from a convention, then spell it out. + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-06"></a>Overall structural guidelines +#### <a href="#04-06">Style 04-06</a> + + +~~~ {.s-rule.do} + +**Do** start small but keep in mind where the app is heading down the road. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** have a near term view of implementation and a long term vision. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** put all of the app's code in a folder named `src`. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** creating a folder for a component when it has multiple accompanying files (`.ts`, `.html`, `.css` and `.spec`). + + +~~~ + + +<div class='s-why'> + **Why?** Helps keep the app structure small and easy to maintain in the early stages, while being easy to evolve as the app grows. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Components often have four files (e.g. `*.html`, `*.css`, `*.ts`, and `*.spec.ts`) and can clutter a folder quickly. + +</div> + + + +{@a file-tree} +Here is a compliant folder and file structure: + +<aio-filetree> + + <aio-folder> + <project root> + <aio-folder> + src + <aio-folder> + app + <aio-folder> + core + <aio-file> + core.module.ts + </aio-file> + + + <aio-file> + exception.service.ts|spec.ts + </aio-file> + + + <aio-file> + user-profile.service.ts|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + heroes + <aio-folder> + hero + <aio-file> + hero.component.ts|html|css|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + hero-list + <aio-file> + hero-list.component.ts|html|css|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + shared + <aio-file> + hero-button.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + hero.model.ts + </aio-file> + + + <aio-file> + hero.service.ts|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + heroes.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + heroes.module.ts + </aio-file> + + + <aio-file> + heroes-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + shared + <aio-file> + shared.module.ts + </aio-file> + + + <aio-file> + init-caps.pipe.ts|spec.ts + </aio-file> + + + <aio-file> + text-filter.component.ts|spec.ts + </aio-file> + + + <aio-file> + text-filter.service.ts|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + villains + <aio-folder> + villain + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-folder> + villain-list + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-folder> + shared + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-file> + villains.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + villains.module.ts + </aio-file> + + + <aio-file> + villains-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + app.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + app-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules/... + </aio-file> + + + <aio-file> + ... + </aio-file> + + + </aio-folder> + + +</aio-filetree> + + +While components in dedicated folders are widely preferred, +another option for small apps is to keep components flat (not in a dedicated folder). +This adds up to four files to the existing folder, but also reduces the folder nesting. +Whatever you choose, be consistent. +<a href="#toc">Back to top</a> +### <a id="04-07"></a>_Folders-by-feature_ structure +#### <a href="#04-07">Style 04-07</a> + + +~~~ {.s-rule.do} + +**Do** create folders named for the feature area they represent. + + +~~~ + + +<div class='s-why'> + **Why?** A developer can locate the code, identify what each file represents + at a glance, the structure is as flat as it can be, and there are no repetitive or redundant names. + +</div> + + +<div class='s-why'> + **Why?** The LIFT guidelines are all covered. + +</div> + + +<div class='s-why'> + **Why?** Helps reduce the app from becoming cluttered through organizing the content and keeping them aligned with the LIFT guidelines. + +</div> + + +<div class='s-why'> + **Why?** When there are a lot of files (e.g. 10+), locating them is easier with a consistent folder structure and more difficult in a flat structure. + +</div> + + + +~~~ {.s-rule.do} + +**Do** create an Angular module for each feature area. + + +~~~ + + +<div class='s-why'> + **Why?** Angular modules make it easy to lazy load routable features. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Angular modules make it easier to isolate, test, and re-use features. + +</div> + + +<div class='file-tree-reference'> + <a href="#file-tree"> Refer to this _folder and file structure_ example. </a> +</div> + +<a href="#toc">Back to top</a> +### <a id="04-08"></a>App _root module_ +#### <a href="#04-08">Style 04-08</a> + + +~~~ {.s-rule.do} + +**Do** create an Angular module in the app's root folder (e.g., in `/src/app`). + + +~~~ + + +<div class='s-why'> + **Why?** Every app requires at least one root Angular module. + +</div> + + + +~~~ {.s-rule.consider} + +**Consider** naming the root module `app.module.ts`. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Makes it easier to locate and identify the root module. + +</div> + + + +{@example 'style-guide/ts/src/04-08/app/app.module.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="04-09"></a>Feature modules +#### <a href="#04-09">Style 04-09</a> + +~~~ {.s-rule.do} + +**Do** create an Angular module for all distinct features in an application (e.g. `Heroes` feature). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** place the feature module in the same named folder as the feature area (.e.g `app/heroes`). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name the feature module file reflecting the name of the feature area and folder (e.g. `app/heroes/heroes.module.ts`) + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name the feature module symbol reflecting the name of the feature area, folder, and file (e.g. `app/heroes/heroes.module.ts` defines `HeroesModule`) + + +~~~ + + +<div class='s-why'> + **Why?** A feature module can expose or hide its implementation from other modules. + +</div> + + +<div class='s-why'> + **Why?** A feature module identifies distinct sets of related components that comprise the feature area. + +</div> + + +<div class='s-why'> + **Why?** A feature module can easily be routed to both eagerly and lazily. + +</div> + + +<div class='s-why'> + **Why?** A feature module defines clear boundaries between specific functionality and other application features. + +</div> + + +<div class='s-why'> + **Why?** A feature module helps clarify and make it easier to assign development responsibilities to different teams. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** A feature module can easily be isolated for testing. + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-10"></a>Shared feature module +#### <a href="#04-10">Style 04-10</a> + + +~~~ {.s-rule.do} + +**Do** create a feature module named `SharedModule` in a `shared` folder (e.g. `app/shared/shared.module.ts` defines `SharedModule`). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** declare components, directives, and pipes in a shared module when those +items will be re-used and referenced by the components declared in other feature modules. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** using the name SharedModule, when the contents of a shared +module are referenced across the entire application. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** not provide services in shared modules. Services are usually +singletons that are provided once for the entire application or +in a particular feature module. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** import all modules required by the assets in the `SharedModule` (e.g. `CommonModule` and `FormsModule`). + + +~~~ + + +<div class='s-why'> + **Why?** `SharedModule` will contain components, directives and pipes that may need features from another common module (e.g. `ngFor` in `CommonModule`). + +</div> + + + +~~~ {.s-rule.do} + +**Do** declare all components, directives, and pipes in the `SharedModule`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** export all symbols from the `SharedModule` that other feature modules need to use. + + +~~~ + + +<div class='s-why'> + **Why?** `SharedModule` exists to make commonly used components, directives and pipes available for use in the templates of components in many other modules. + +</div> + + + +~~~ {.s-rule.avoid} + +**Avoid** specifying app-wide singleton providers in a `SharedModule`. Intentional singletons are OK. Take care. + + +~~~ + + +<div class='s-why'> + **Why?** A lazy loaded feature module that imports that shared module will make its own copy of the service and likely have undesireable results. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** You don't want each module to have its own separate instance of singleton services. + Yet there is a real danger of that happening if the `SharedModule` provides a service. + +</div> + + +<aio-filetree> + + <aio-folder> + src + <aio-folder> + app + <aio-folder> + shared + <aio-file> + shared.module.ts + </aio-file> + + + <aio-file> + init-caps.pipe.ts|spec.ts + </aio-file> + + + <aio-file> + text-filter.component.ts|spec.ts + </aio-file> + + + <aio-file> + text-filter.service.ts|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + app.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + app-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + </aio-folder> + + + <aio-file> + ... + </aio-file> + + +</aio-filetree> + + +<md-tab-group> + + <md-tab label="app/shared/shared.module.ts"> + {@example 'style-guide/ts/src/04-10/app/shared/shared.module.ts'} + </md-tab> + + + <md-tab label="app/shared/init-caps.pipe.ts"> + {@example 'style-guide/ts/src/04-10/app/shared/init-caps.pipe.ts'} + </md-tab> + + + <md-tab label="app/shared/filter-text/filter-text.component.ts"> + {@example 'style-guide/ts/src/04-10/app/shared/filter-text/filter-text.component.ts'} + </md-tab> + + + <md-tab label="app/shared/filter-text/filter-text.service.ts"> + {@example 'style-guide/ts/src/04-10/app/shared/filter-text/filter-text.service.ts'} + </md-tab> + + + <md-tab label="app/heroes/heroes.component.ts"> + {@example 'style-guide/ts/src/04-10/app/heroes/heroes.component.ts'} + </md-tab> + + + <md-tab label="app/heroes/heroes.component.html"> + {@example 'style-guide/ts/src/04-10/app/heroes/heroes.component.html'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="04-11"></a>Core feature module +#### <a href="#04-11">Style 04-11</a> + + +~~~ {.s-rule.consider} + +**Consider** collecting numerous, auxiliary, single-use classes inside a core module +to simplify the apparent structure of a feature module. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** calling the application-wide core module, `CoreModule`. +Importing `CoreModule` into the root `AppModule` reduces its complexity +and emphasizes its role as orchestrator of the application as a whole. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** create a feature module named `CoreModule` in a `core` folder (e.g. `app/core/core.module.ts` defines `CoreModule`). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** put a singleton service whose instance wil be shared throughout the application in the `CoreModule` (e.g. `ExceptionService` and `LoggerService`). + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** import all modules required by the assets in the `CoreModule` (e.g. `CommonModule` and `FormsModule`). + + +~~~ + + +<div class='s-why'> + **Why?** `CoreModule` provides one or more singleton services. Angular registers the providers with the app root injector, making a singleton instance of each service available to any component that needs them, whether that component is eagerly or lazily loaded. + +</div> + + +<div class='s-why'> + **Why?** `CoreModule` will contain singleton services. When a lazy loaded module imports these, it will get a new instance and not the intended app-wide singleton. + +</div> + + + +~~~ {.s-rule.do} + +**Do** gather application-wide, single use components in the `CoreModule`. +Import it once (in the `AppModule`) when the app starts and never import it anywhere else. (e.g. `NavComponent` and `SpinnerComponent`). + + +~~~ + + +<div class='s-why'> + **Why?** Real world apps can have several single-use components (e.g., spinners, message toasts, and modal dialogs) that appear only in the `AppComponent` template. + They are not imported elsewhere so they're not shared in that sense. + Yet they're too big and messy to leave loose in the root folder. + +</div> + + + +~~~ {.s-rule.avoid} + +**Avoid** importing the `CoreModule` anywhere except in the `AppModule`. + + +~~~ + + +<div class='s-why'> + **Why?** A lazily loaded feature module that directly imports the `CoreModule` will make its own copy of services and likely have undesireable results. + +</div> + + +<div class='s-why'> + **Why?** An eagerly loaded feature module already has access to the `AppModule`'s injector, and thus the `CoreModule`'s services. + +</div> + + + +~~~ {.s-rule.do} + +**Do** export all symbols from the `CoreModule` that the `AppModule` will import and make available for other feature modules to use. + + +~~~ + + +<div class='s-why'> + **Why?** `CoreModule` exists to make commonly used singleton services available for use in the many other modules. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** You want the entire app to use the one, singleton instance. + You don't want each module to have its own separate instance of singleton services. + Yet there is a real danger of that happening accidentally if the `CoreModule` provides a service. + + +</div> + + +<aio-filetree> + + <aio-folder> + src + <aio-folder> + app + <aio-folder> + core + <aio-file> + core.module.ts + </aio-file> + + + <aio-file> + logger.service.ts|spec.ts + </aio-file> + + + <aio-folder> + nav + <aio-file> + nav.component.ts|html|css|spec.ts + </aio-file> + + + </aio-folder> + + + <aio-folder> + spinner + <aio-file> + spinner.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + spinner.service.ts|spec.ts + </aio-file> + + + </aio-folder> + + + </aio-folder> + + + <aio-file> + app.component.ts|html|css|spec.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + app-routing.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + </aio-folder> + + + <aio-file> + ... + </aio-file> + + +</aio-filetree> + + +<md-tab-group> + + <md-tab label="app/app.module.ts"> + {@example 'style-guide/ts/src/04-11/app/app.module.ts' region='example'} + </md-tab> + + + <md-tab label="app/core/core.module.ts"> + {@example 'style-guide/ts/src/04-11/app/core/core.module.ts'} + </md-tab> + + + <md-tab label="app/core/logger.service.ts"> + {@example 'style-guide/ts/src/04-11/app/core/logger.service.ts'} + </md-tab> + + + <md-tab label="app/core/nav/nav.component.ts"> + {@example 'style-guide/ts/src/04-11/app/core/nav/nav.component.ts'} + </md-tab> + + + <md-tab label="app/core/nav/nav.component.html"> + {@example 'style-guide/ts/src/04-11/app/core/nav/nav.component.html'} + </md-tab> + + + <md-tab label="app/core/spinner/spinner.component.ts"> + {@example 'style-guide/ts/src/04-11/app/core/spinner/spinner.component.ts'} + </md-tab> + + + <md-tab label="app/core/spinner/spinner.component.html"> + {@example 'style-guide/ts/src/04-11/app/core/spinner/spinner.component.html'} + </md-tab> + + + <md-tab label="app/core/spinner/spinner.service.ts"> + {@example 'style-guide/ts/src/04-11/app/core/spinner/spinner.service.ts'} + </md-tab> + + +</md-tab-group> + + +`AppModule` is a little smaller because many app/root classes have moved to other modules. +`AppModule` is stable because you will add future components and providers to other modules, not this one. +`AppModule` delegates to imported modules rather than doing work. +`AppModule` is focused on its main task, orchestrating the app as a whole. +<a href="#toc">Back to top</a> +### <a id="04-12"></a>Prevent re-import of the core module +#### <a href="#04-12">Style 04-12</a> +Only the root `AppModule` should import the `CoreModule`. + + +~~~ {.s-rule.do} + +**Do** guard against reimporting of `CoreModule` and fail fast by adding guard logic. + + +~~~ + + +<div class='s-why' class='s-why'> + **Why?** Guards against reimporting of the `CoreModule`. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Guards against creating multiple instances of assets intended to be singletons. + +</div> + + +<md-tab-group> + + <md-tab label="app/core/module-import-guard.ts"> + {@example 'style-guide/ts/src/04-12/app/core/module-import-guard.ts'} + </md-tab> + + + <md-tab label="app/core/core.module.ts"> + {@example 'style-guide/ts/src/04-12/app/core/core.module.ts'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="04-13"></a>Lazy Loaded folders +#### <a href="#04-13">Style 04-13</a> +A distinct application feature or workflow may be *lazy loaded* or *loaded on demand* rather than when the application starts. + + +~~~ {.s-rule.do} + +**Do** put the contents of lazy loaded features in a *lazy loaded folder*. +A typical *lazy loaded folder* contains a *routing component*, its child components, and their related assets and modules. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** The folder makes it easy to identify and isolate the feature content. + +</div> + +<a href="#toc">Back to top</a> +### <a id="04-14"></a>Never directly import lazy loaded folders +#### <a href="#04-14">Style 04-14</a> + + +~~~ {.s-rule.avoid} + +**Avoid** allowing modules in sibling and parent folders to directly import a module in a *lazy loaded feature*. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Directly importing and using a module will load it immediately when the intention is to load it on demand. + +</div> + +<a href="#toc">Back to top</a> +## Components + +### <a id="05-02"></a>Component selector names +#### <a href="#05-02">Style 05-02</a> + + +~~~ {.s-rule.do} + +**Do** use _dashed-case_ or _kebab-case_ for naming the element selectors of components. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Keeps the element names consistent with the specification for [Custom Elements](https://www.w3.org/TR/custom-elements/). + +</div> + + + +{@example 'style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts' region='example'} + + +<md-tab-group> + + <md-tab label="app/heroes/shared/hero-button/hero-button.component.ts"> + {@example 'style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts' region='example'} + </md-tab> + + + <md-tab label="app/app.component.html"> + {@example 'style-guide/ts/src/05-02/app/app.component.html'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="05-03"></a>Components as elements +#### <a href="#05-03">Style 05-03</a> + + +~~~ {.s-rule.do} + +**Do** give components an _element_ selector, as opposed to _attribute_ or _class_ selectors. + + +~~~ + + +<div class='s-why'> + **Why?** components have templates containing HTML and optional Angular template syntax. + They display content. + Developers place components on the page as they would native HTML elements and WebComponents. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** It is easier to recognize that a symbol is a component by looking at the template's html. + +</div> + + + +{@example 'style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-03/app/app.component.avoid.html'} + + +<md-tab-group> + + <md-tab label="app/heroes/shared/hero-button/hero-button.component.ts"> + {@example 'style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts' region='example'} + </md-tab> + + + <md-tab label="app/app.component.html"> + {@example 'style-guide/ts/src/05-03/app/app.component.html'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="05-04"></a>Extract templates and styles to their own files +#### <a href="#05-04">Style 05-04</a> + + +~~~ {.s-rule.do} + +**Do** extract templates and styles into a separate file, when more than 3 lines. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name the template file `[component-name].component.html`, where [component-name] is the component name. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name the style file `[component-name].component.css`, where [component-name] is the component name. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** specify _component-relative_ URLs, prefixed with `./`, and add `moduleId: module.id` to the component metadata. + + +~~~ + + +<div class='s-why'> + **Why?** Large, inline templates and styles obscure the component's purpose and implementation, reducing readability and maintainability. + +</div> + + +<div class='s-why'> + **Why?** In most editors, syntax hints and code snippets aren't available when developing inline templates and styles. + The Angular TypeScript Language Service (forthcoming) promises to overcome this deficiency for HTML templates + in those editors that support it; it won't help with CSS styles. + +</div> + + +<div class='s-why'> + **Why?** A _component relative_ URL requires no change when you move the component files, as long as the files stay together. + +</div> + + +<div class='s-why'> + **Why?** The JIT compiler requires the `moduleId` for relative URLs; the AOT compiler, + which doesn't need it, safely ignores this property. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** The `./` prefix is standard syntax for relative URLs; don't depend on Angular's current ability to do without that prefix. + + +</div> + + + +{@example 'style-guide/ts/src/05-04/app/heroes/heroes.component.avoid.ts' region='example'} + + +<md-tab-group> + + <md-tab label="app/heroes/heroes.component.ts"> + {@example 'style-guide/ts/src/05-04/app/heroes/heroes.component.ts' region='example'} + </md-tab> + + + <md-tab label="app/heroes/heroes.component.html"> + {@example 'style-guide/ts/src/05-04/app/heroes/heroes.component.html'} + </md-tab> + + + <md-tab label="app/heroes/heroes.component.css"> + {@example 'style-guide/ts/src/05-04/app/heroes/heroes.component.css'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="05-12"></a>Decorate _input_ and _output_ properties +#### <a href="#05-12">Style 05-12</a> + + +~~~ {.s-rule.do} + +**Do** use the `@Input` and `@Output` class decorators instead of the `inputs` and `outputs` properties of the +`@Directive` and `@Component` metadata: + + +~~~ + + + +~~~ {.s-rule.do} + +**Consider** placing `@Input()` or `@Output()` on the same line as the property it decorates. + + +~~~ + + +<div class='s-why'> + **Why?** It is easier and more readable to identify which properties in a class are inputs or outputs. + +</div> + + +<div class='s-why'> + **Why?** If you ever need to rename the property or event name associated with + `@Input` or `@Output`, you can modify it in a single place. + +</div> + + +<div class='s-why'> + **Why?** The metadata declaration attached to the directive is shorter and thus more readable. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Placing the decorator on the same line _usually_ makes for shorter code and still easily identifies the property as an input or output. + Put it on the line above when doing so is clearly more readable. + +</div> + + + +{@example 'style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="05-13"></a>Avoid aliasing _inputs_ and _outputs_ +#### <a href="#05-13">Style 05-13</a> + + +~~~ {.s-rule.avoid} + +**Avoid** _input_ and _output_ aliases except when it serves an important purpose. + + +~~~ + + +<div class='s-why'> + **Why?** Two names for the same property (one private, one public) is inherently confusing. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** You should use an alias when the directive name is also an _input_ property, + and the directive name doesn't describe the property. + +</div> + + + +{@example 'style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-13/app/app.component.avoid.html'} + + +<md-tab-group> + + <md-tab label="app/heroes/shared/hero-button/hero-button.component.ts"> + {@example 'style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts' region='example'} + </md-tab> + + + <md-tab label="app/heroes/shared/hero-button/hero-highlight.directive.ts"> + {@example 'style-guide/ts/src/05-13/app/heroes/shared/hero-highlight.directive.ts'} + </md-tab> + + + <md-tab label="app/app.component.html"> + {@example 'style-guide/ts/src/05-13/app/app.component.html'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="05-14"></a>Member sequence +#### <a href="#05-14">Style 05-14</a> + + +~~~ {.s-rule.do} + +**Do** place properties up top followed by methods. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** place private members after public members, alphabetized. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Placing members in a consistent sequence makes it easy to read and + helps instantly identify which members of the component serve which purpose. + +</div> + + + +{@example 'style-guide/ts/src/05-14/app/shared/toast/toast.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-14/app/shared/toast/toast.component.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="05-15"></a>Delegate complex component logic to services +#### <a href="#05-15">Style 05-15</a> + + +~~~ {.s-rule.do} + +**Do** limit logic in a component to only that required for the view. All other logic should be delegated to services. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** move reusable logic to services and keep components simple and focused on their intended purpose. + + +~~~ + + +<div class='s-why'> + **Why?** Logic may be reused by multiple components when placed within a service and exposed via a function. + +</div> + + +<div class='s-why'> + **Why?** Logic in a service can more easily be isolated in a unit test, while the calling logic in the component can be easily mocked. + +</div> + + +<div class='s-why'> + **Why?** Removes dependencies and hides implementation details from the component. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Keeps the component slim, trim, and focused. + +</div> + + + +{@example 'style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts'} + + + +{@example 'style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="05-16"></a>Don't prefix _output_ properties +#### <a href="#05-16">Style 05-16</a> + + +~~~ {.s-rule.do} + +**Do** name events without the prefix `on`. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** name event handler methods with the prefix `on` followed by the event name. + + +~~~ + + +<div class='s-why'> + **Why?** This is consistent with built-in events such as button clicks. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Angular allows for an [alternative syntax](template-syntax.html#binding-syntax) `on-*`. If the event itself was prefixed with `on` this would result in an `on-onEvent` binding expression. + +</div> + + + +{@example 'style-guide/ts/src/05-16/app/heroes/hero.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-16/app/app.component.avoid.html'} + + +<md-tab-group> + + <md-tab label="app/heroes/hero.component.ts"> + {@example 'style-guide/ts/src/05-16/app/heroes/hero.component.ts' region='example'} + </md-tab> + + + <md-tab label="app/app.component.html"> + {@example 'style-guide/ts/src/05-16/app/app.component.html'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="05-17"></a>Put presentation logic in the component class +#### <a href="#05-17">Style 05-17</a> + + +~~~ {.s-rule.do} + +**Do** put presentation logic in the component class, and not in the template. + + +~~~ + + +<div class='s-why'> + **Why?** Logic will be contained in one place (the component class) instead of being spread in two places. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Keeping the component's presentation logic in the class instead of the template improves testability, maintainability, and reusability. + +</div> + + + +{@example 'style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.ts' region='example'} + +<a href="#toc">Back to top</a> +## Directives +<a href="#toc">Back to top</a> +### <a id="06-01"></a>Use directives to enhance an element +#### <a href="#06-01">Style 06-01</a> + + +~~~ {.s-rule.do} + +**Do** use attribute directives when you have presentation logic without a template. + + +~~~ + + +<div class='s-why'> + **Why?** Attributes directives don't have an associated template. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** An element may have more than one attribute directive applied. + +</div> + + + +{@example 'style-guide/ts/src/06-01/app/shared/highlight.directive.ts' region='example'} + + + +{@example 'style-guide/ts/src/06-01/app/app.component.html'} + +<a href="#toc">Back to top</a> +### <a id="06-03"></a>_HostListener_/_HostBinding_ decorators versus _host_ metadata +#### <a href="#06-03">Style 06-03</a> + + +~~~ {.s-rule.consider} + +**Consider** preferring the `@HostListener` and `@HostBinding` to the +`host` property of the `@Directive` and `@Component` decorators. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** be consistent in your choice. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** The property associated with `@HostBinding` or the method associated with `@HostListener` + can be modified only in a single place - in the directive's class. + If you use the `host` metadata property, you must modify both the property declaration inside the controller, + and the metadata associated with the directive. + +</div> + + + +{@example 'style-guide/ts/src/06-03/app/shared/validator.directive.ts'} + +Compare with the less preferred `host` metadata alternative. + +<div class='s-why' class='s-why-last'> + **Why?** The `host` metadata is only one term to remember and doesn't require extra ES imports. + +</div> + + + +{@example 'style-guide/ts/src/06-03/app/shared/validator2.directive.ts'} + +<a href="#toc">Back to top</a> +## Services + +### <a id="07-01"></a>Services are singletons +#### <a href="#07-01">Style 07-01</a> + + +~~~ {.s-rule.do} + +**Do** use services as singletons within the same injector. Use them for sharing data and functionality. + + +~~~ + + +<div class='s-why'> + **Why?** Services are ideal for sharing methods across a feature area or an app. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** Services are ideal for sharing stateful in-memory data. + +</div> + + + +{@example 'style-guide/ts/src/07-01/app/heroes/shared/hero.service.ts' region='example'} + +<a href="#toc">Back to top</a> +### <a id="07-02"></a>Single responsibility +#### <a href="#07-02">Style 07-02</a> + + +~~~ {.s-rule.do} + +**Do** create services with a single responsibility that is encapsulated by its context. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** create a new service once the service begins to exceed that singular purpose. + + +~~~ + + +<div class='s-why'> + **Why?** When a service has multiple responsibilities, it becomes difficult to test. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** When a service has multiple responsibilities, every component or service that injects it now carries the weight of them all. + +</div> + +<a href="#toc">Back to top</a> +### <a id="07-03"></a>Providing a service +#### <a href="#07-03">Style 07-03</a> + + +~~~ {.s-rule.do} + +**Do** provide services to the Angular injector at the top-most component where they will be shared. + + +~~~ + + +<div class='s-why'> + **Why?** The Angular injector is hierarchical. + +</div> + + +<div class='s-why'> + **Why?** When providing the service to a top level component, + that instance is shared and available to all child components of that top level component. + +</div> + + +<div class='s-why'> + **Why?** This is ideal when a service is sharing methods or state. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** This is not ideal when two different components need different instances of a service. In this scenario it would be better to provide the service at the component level that needs the new and separate instance. + +</div> + + +<md-tab-group> + + <md-tab label="app/app.component.ts"> + {@example 'style-guide/ts/src/07-03/app/app.component.ts'} + </md-tab> + + + <md-tab label="app/heroes/hero-list/hero-list.component.ts"> + {@example 'style-guide/ts/src/07-03/app/heroes/hero-list/hero-list.component.ts'} + </md-tab> + + +</md-tab-group> + +<a href="#toc">Back to top</a> +### <a id="07-04"></a>Use the @Injectable() class decorator +#### <a href="#07-04">Style 07-04</a> + + +~~~ {.s-rule.do} + +**Do** use the `@Injectable` class decorator instead of the `@Inject` parameter decorator when using types as tokens for the dependencies of a service. + + +~~~ + + +<div class='s-why'> + **Why?** The Angular Dependency Injection (DI) mechanism resolves a service's own + dependencies based on the declared types of that service's constructor parameters. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** When a service accepts only dependencies associated with type tokens, the `@Injectable()` syntax is much less verbose compared to using `@Inject()` on each individual constructor parameter. + +</div> + + + +{@example 'style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.ts' region='example'} + +<a href="#toc">Back to top</a> +## Data Services + +### <a id="08-01"></a>Talk to the server through a service +#### <a href="#08-01">Style 08-01</a> + + +~~~ {.s-rule.do} + +**Do** refactor logic for making data operations and interacting with data to a service. + + +~~~ + + + +~~~ {.s-rule.do} + +**Do** make data services responsible for XHR calls, local storage, stashing in memory, or any other data operations. + + +~~~ + + +<div class='s-why'> + **Why?** The component's responsibility is for the presentation and gathering of information for the view. It should not care how it gets the data, just that it knows who to ask for it. Separating the data services moves the logic on how to get it to the data service, and lets the component be simpler and more focused on the view. + +</div> + + +<div class='s-why'> + **Why?** This makes it easier to test (mock or real) the data calls when testing a component that uses a data service. + +</div> + + +<div class='s-why' class='s-why-last'> + **Why?** The details of data management, such as headers, HTTP methods, + caching, error handling, and retry logic, are irrelevant to components + and other data consumers. + + A data service encapsulates these details. It's easier to evolve these + details inside the service without affecting its consumers. And it's + easier to test the consumers with mock service implementations. + +</div> + +<a href="#toc">Back to top</a> +## Lifecycle hooks + +Use Lifecycle hooks to tap into important events exposed by Angular. +<a href="#toc">Back to top</a> +### <a id="09-01"></a>Implement lifecycle hook interfaces +#### <a href="#09-01">Style 09-01</a> + + +~~~ {.s-rule.do} + +**Do** implement the lifecycle hook interfaces. + + +~~~ + + +<div class='s-why' class='s-why-last'> + **Why?** Lifecycle interfaces prescribe typed method + signatures. use those signatures to flag spelling and syntax mistakes. + +</div> + + + +{@example 'style-guide/ts/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts' region='example'} + + + +{@example 'style-guide/ts/src/09-01/app/heroes/shared/hero-button/hero-button.component.ts' region='example'} + +<a href="#toc">Back to top</a> +## Appendix + +Useful tools and tips for Angular. +<a href="#toc">Back to top</a> +### <a id="A-01"></a>Codelyzer +#### <a href="#A-01">Style A-01</a> + + +~~~ {.s-rule.do} + +**Do** use [codelyzer](https://www.npmjs.com/package/codelyzer) to follow this guide. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** adjusting the rules in codelyzer to suit your needs. + + +~~~ + +<a href="#toc">Back to top</a> +### <a id="A-02"></a>File templates and snippets +#### <a href="#A-02">Style A-02</a> + + +~~~ {.s-rule.do} + +**Do** use file templates or snippets to help follow consistent styles and patterns. Here are templates and/or snippets for some of the web development editors and IDEs. + + +~~~ + + + +~~~ {.s-rule.consider} + +**Consider** using [snippets](https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2) for [Visual Studio Code](https://code.visualstudio.com/) that follow these styles and guidelines. + +<a href="https://marketplace.visualstudio.com/items?itemName=johnpapa.Angular2"> + <img src="https://github.com/johnpapa/vscode-angular2-snippets/raw/master/images/use-extension.gif" width="80%" alt="Use Extension"> +</a> + +**Consider** using [snippets](https://atom.io/packages/angular-2-typescript-snippets) for [Atom](https://atom.io/) that follow these styles and guidelines. + +**Consider** using [snippets](https://github.com/orizens/sublime-angular2-snippets) for [Sublime Text](http://www.sublimetext.com/) that follow these styles and guidelines. + +**Consider** using [snippets](https://github.com/mhartington/vim-angular2-snippets) for [Vim](http://www.vim.org/) that follow these styles and guidelines. + + +~~~ + +<a href="#toc">Back to top</a> \ No newline at end of file diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md new file mode 100644 index 0000000000..d77bb5e599 --- /dev/null +++ b/aio/content/guide/template-syntax.md @@ -0,0 +1,1899 @@ +@title +Template Syntax + +@intro +Learn how to write templates that display data and consume user events with the help of data binding. + +@description + +<style> + h4 {font-size: 17px !important; text-transform: none !important;} + .syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; } + h4 .syntax { font-size: 100%; } + +</style> + +The Angular application manages what the user sees and can do, achieving this through the interaction of a +component class instance (the *component*) and its user-facing template. + +You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM). +In Angular, the component plays the part of the controller/viewmodel, and the template represents the view. + + +{@a toc} +### Table of contents +This guide covers the basic elements of the Angular template syntax, elements you'll need to construct the view: + +* [HTML in templates](#html) +* [Interpolation ( <span class="syntax">{{...}}</span> )](#interpolation) +* [Template expressions](#template-expressions) +* [Template statements](#template-statements) +* [Binding syntax](#binding-syntax) +* [Property binding ( <span class="syntax">[property]</span> )](#property-binding) +* [Attribute, class, and style bindings](#other-bindings) +* [Event binding ( <span class="syntax">(event)</span> )](#event-binding) +* [Two-way data binding ( <span class="syntax">[(...)]</span> )](#two-way) +* [Built-in directives](#directives) + * [Attribute directives](#attribute-directives) + * [NgClass](#ngClass) + * [NgStyle](#ngStyle) + * [NgModel (<span class="syntax">[(ngModel)]</span>) ](#ngModel) + * [Structural directives](#structural-directives) + * [NgIf](#ngIf) + * [NgFor](#ngFor) + * [Template input variables](#template-input-variables) + * [microsyntax](#microsyntax) + * [The NgSwitch directives](#ngSwitch) +* [Template reference variables ( <span class="syntax">#var</span> )](#ref-vars) +* [Input and output properties ( <span class="syntax">@Input</span> and <span class="syntax">@Output</span> )](#inputs-outputs) +* [Template expression operators](#expression-operators) + * [pipe ( <span class="syntax">|</span> )](#pipe) + * [safe navigation operator ( <span class="syntax">?.</span> )](#safe-navigation-operator) + +The <live-example></live-example> +demonstrates all of the syntax and code snippets described in this guide. + +<div class='l-hr'> + +</div> + + + +{@a html} +## HTML in templates +HTML is the language of the Angular template. +The [QuickStart](../quickstart.html) application has a template that is pure HTML: + +<code-example language="html" escape="html"> + <h1>Hello Angular</h1> + +</code-example> + +Almost all HTML syntax is valid template syntax. +The `<script>` element is a notable exception; +it is forbidden, eliminating the risk of script injection attacks. +In practice, `<script>` is ignored and a warning appears in the browser console. + +Some legal HTML doesn't make much sense in a template. +The `<html>`, `<body>`, and `<base>` elements have no useful role. +Pretty much everything else is fair game. + +You can extend the HTML vocabulary of your templates with components and directives that appear as new elements and attributes. +In the following sections, you'll learn how to get and set DOM (Document Object Model) values dynamically through data binding. + +Begin with the first form of data binding—interpolation—to see how much richer template HTML can be. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a interpolation} +## Interpolation ( <span class="syntax">{{...}}</span> ) +You met the double-curly braces of interpolation, `{{` and `}}`, early in your Angular education. + +{@example 'template-syntax/ts/src/app/app.component.html' region='first-interpolation'} + +You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='title+image'} + +The material between the braces is often the name of a component property. Angular replaces that name with the +string value of the corresponding component property. In the example above, Angular evaluates the `title` and `heroImageUrl` properties +and "fills in the blanks", first displaying a bold application title and then a heroic image. + +More generally, the material between the braces is a **template expression** that Angular first **evaluates** +and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers within braces: + +{@example 'template-syntax/ts/src/app/app.component.html' region='sum-1'} + +The expression can invoke methods of the host component with `getVal()` as seen here: + +{@example 'template-syntax/ts/src/app/app.component.html' region='sum-2'} + +Angular evaluates all expressions in double curly braces, converts the expression results to strings, and links them with neighboring literal strings. Finally, +it assigns this composite interpolated result to an **element or directive property**. + +You appear to be inserting the result between element tags and assigning it to attributes. +It's convenient to think so, and you rarely suffer for this mistake. +Though this is not exactly true. Interpolation is a special syntax that Angular converts into a +[property binding](#property-binding), and is explained below. + +But first, let's take a closer look at template expressions and statements. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a template-expressions} +## Template expressions +A template **expression** produces a value. +Angular executes the expression and assigns it to a property of a binding target; +the target might be an HTML element, a component, or a directive. + +The interpolation braces in `{{1 + 1}}` surround the template expression `1 + 1`. +In the [property binding](#property-binding) section below, +a template expression appears in quotes to the right of the `=` symbol as in `[property]="expression"`. + +You write these template expressions in a language that looks like #{_JavaScript}. +Many #{_JavaScript} expressions are legal template expressions, but not all. + +#{_JavaScript} expressions that have or promote side effects are prohibited, +including: + +* assignments (`=`, `+=`, `-=`, ...) +* !{__new_op} +* chaining expressions with !{__chaining_op} +* increment and decrement operators (`++` and `--`) +Other notable differences from #{_JavaScript} syntax include: + +<h3 id='expression-context'> + Expression context +</h3> + +The *expression context* is typically the _component_ instance. +In the following snippets, the `title` within double-curly braces and the +`isUnchanged` in quotes refer to properties of the `AppComponent`. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='context-component-expression'} + +An expression may also refer to properties of the _template's_ context +such as a [template input variable](#template-input-variable) (`let hero`) +or a [template reference variable](#ref-vars) (`#heroInput`). + +{@example 'template-syntax/ts/src/app/app.component.html' region='context-var'} + +The context for terms in an expression is a blend of the _template variables_, +the directive's _context_ object (if it has one), and the component's _members_. +If you reference a name that belongs to more than one of these namespaces, +the template variable name takes precedence, followed by a name in the directive's' _context_, +and, lastly, the component's member names. + +The previous example presents such a name collision. The component has a `hero` property and the `*ngFor` defines a `hero` template variable. The `hero` in `{{hero}}` refers to the template input variable, not the component's property. +<a href="#toc">back to top</a> + +{@a no-side-effects} + + +{@a expression-guidelines} +### Expression guidelines +Template expressions can make or break an application. +Please follow these guidelines: + +* [No visible side effects](#no-visible-side-effects) +* [Quick execution](#quick-execution) +* [Simplicity](#simplicity) +* [Idempotence](#idempotence) + +The only exceptions to these guidelines should be in specific circumstances that you thoroughly understand. + +#### No visible side effects + +A template expression should not change any application state other than the value of the +target property. + +This rule is essential to Angular's "unidirectional data flow" policy. +You should never worry that reading a component value might change some other displayed value. +The view should be stable throughout a single rendering pass. + +#### Quick execution +Angular executes template expressions after every change detection cycle. +Change detection cycles are triggered by many asynchronous activities such as +promise resolutions, http results, timer events, keypresses and mouse moves. + +Expressions should finish quickly or the user experience may drag, especially on slower devices. +Consider caching values computed from other values when the computation is expensive. + +#### Simplicity +Although it's possible to write quite complex template expressions, you should avoid them. + +A property name or method call should be the norm. +An occasional Boolean negation (`!`) is OK. +Otherwise, confine application and business logic to the component itself, +where it will be easier to develop and test. + +#### Idempotence +An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because +it is free of side effects and improves Angular's change detection performance. + +In Angular terms, an idempotent expression always returns *exactly the same thing* until +one of its dependent values changes.Dependent values should not change during a single turn of the event loop. +If an idempotent expression returns a string or a number, it returns the same string or number +when called twice in a row. If the expression returns an object (including #{_an} `#{_Array}`), +it returns the same object *reference* when called twice in a row. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a template-statements} +## Template statements + +A template **statement** responds to an **event** raised by a binding target +such as an element, component, or directive. +You'll see template statements in the [event binding](#event-binding) section, +appearing in quotes to the right of the `=` symbol as in `(event)="statement"`. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='context-component-statement'} + +A template statement *has a side effect*. +That's the whole point of an event. +It's how you update application state from user action. + +Responding to events is the other side of Angular's "unidirectional data flow". +You're free to change anything, anywhere, during this turn of the event loop. + +Like template expressions, template *statements* use a language that looks like #{_JavaScript}. +The template statement parser is different than the template expression parser and +specifically supports both basic assignment (`=`) and chaining expressions +(with !{__chaining_op}). + +However, certain #{_JavaScript} syntax is not allowed: +* !{__new_op} +* increment and decrement operators, `++` and `--` +* operator assignment, such as `+=` and `-=` +* the bitwise operators `|` and `&` +* the [template expression operators](#expression-operators) +### Statement context + +As with expressions, statements can refer only to what's in the statement context +such as an event handling method of the component instance. +The *statement context* is typically the component instance. +The *deleteHero* in `(click)="deleteHero()"` is a method of the data-bound component. + +{@example 'template-syntax/ts/src/app/app.component.html' region='context-component-statement'} + +The statement context may also refer to properties of the template's own context. +In the following examples, the template `$event` object, +a [template input variable](#template-input-variable) (`let hero`), +and a [template reference variable](#ref-vars) (`#heroForm`) +are passed to an event handling method of the component. + +{@example 'template-syntax/ts/src/app/app.component.html' region='context-var-statement'} + +Template context names take precedence over component context names. +In `deleteHero(hero)` above, the `hero` is the template input variable, not the component's `hero` property. +### Statement guidelines + +As with expressions, avoid writing complex template statements. +A method call or simple property assignment should be the norm. + +Now that you have a feel for template expressions and statements, +you're ready to learn about the varieties of data binding syntax beyond interpolation. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a binding-syntax} +## Binding syntax: An overview +Data binding is a mechanism for coordinating what users see with application data values. +While you could push values to and pull values from HTML, +the application is easier to write, read, and maintain if you turn these chores over to a binding framework. +You simply declare bindings between binding sources and target HTML elements and let the framework do the work. + +Angular provides many kinds of data binding. +This guide covers most of them, after a high-level view of Angular data binding and its syntax. + +Binding types can be grouped into three categories distinguished by the direction of data flow: +from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _view-to-source-to-view_. +: +<style> + td, th {vertical-align: top} +</style> + + +<table width="100%"> + + <col width="30%"> + + </col> + + + <col width="50%"> + + </col> + + + <col width="20%"> + + </col> + + + <tr> + + <th> + Data direction + </th> + + + <th> + Syntax + </th> + + + <th> + Type + </th> + + + </tr> + + + <tr> + + <td> + One-way<br>from data source<br>to view target + </td> + + + <td> + + <code-example> + {{expression}} + [target] = "expression" + bind-target = "expression" + </code-example> + + + </td> + + + <td> + Interpolation<br> + Property<br> + Attribute<br> + Class<br> + Style + </td> + + + <tr> + + <td> + One-way<br>from view target<br>to data source + </td> + + + <td> + + <code-example> + (target) = "statement" + on-target = "statement" + </code-example> + + + </td> + + + <td> + Event + </td> + + + </tr> + + + <tr> + + <td> + Two-way + </td> + + + <td> + + <code-example> + [(target)] = "expression" + bindon-target = "expression" + </code-example> + + + </td> + + + <td> + Two-way + </td> + + + </tr> + + + </tr> + + +</table> + +Binding types other than interpolation have a **target name** to the left of the equal sign, +either surrounded by punctuation (`[]`, `()`) or preceded by a prefix (`bind-`, `on-`, `bindon-`). + +The target name is the name of a _property_. It may look like the name of an _attribute_ but it never is. +To appreciate the difference, you must develop a new way to think about template HTML. + +### A new mental model + +With all the power of data binding and the ability to extend the HTML vocabulary +with custom markup, it is tempting to think of template HTML as *HTML Plus*. + +It really *is* HTML Plus. +But it's also significantly different than the HTML you're used to. +It requires a new mental model. + +In the normal course of HTML development, you create a visual structure with HTML elements, and +you modify those elements by setting element attributes with string constants. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='img+button'} + +You still create a structure and initialize attribute values this way in Angular templates. + +Then you learn to create new elements with components that encapsulate HTML +and drop them into templates as if they were native HTML elements. + +{@example 'template-syntax/ts/src/app/app.component.html' region='hero-detail-1'} + +That's HTML Plus. + +Then you learn about data binding. The first binding you meet might look like this: + + +{@example 'template-syntax/ts/src/app/app.component.html' region='disabled-button-1'} + +You'll get to that peculiar bracket notation in a moment. Looking beyond it, +your intuition suggests that you're binding to the button's `disabled` attribute and setting +it to the current value of the component's `isUnchanged` property. + +Your intuition is incorrect! Your everyday HTML mental model is misleading. +In fact, once you start data binding, you are no longer working with HTML *attributes*. You aren't setting attributes. +You are setting the *properties* of DOM elements, components, and directives. + +### HTML attribute vs. DOM property + +The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works. + +**Attributes are defined by HTML. Properties are defined by the DOM (Document Object Model).** + +* A few HTML attributes have 1:1 mapping to properties. `id` is one example. + +* Some HTML attributes don't have corresponding properties. `colspan` is one example. + +* Some DOM properties don't have corresponding attributes. `textContent` is one example. + +* Many HTML attributes appear to map to properties ... but not in the way you might think! + +That last category is confusing until you grasp this general rule: + +**Attributes *initialize* DOM properties and then they are done. +Property values can change; attribute values can't.** + +For example, when the browser renders `<input type="text" value="Bob">`, it creates a +corresponding DOM node with a `value` property *initialized* to "Bob". + +When the user enters "Sally" into the input box, the DOM element `value` *property* becomes "Sally". +But the HTML `value` *attribute* remains unchanged as you discover if you ask the input element +about that attribute: `input.getAttribute('value') // returns "Bob"` + +The HTML attribute `value` specifies the *initial* value; the DOM `value` property is the *current* value. + +The `disabled` attribute is another peculiar example. A button's `disabled` *property* is +`false` by default so the button is enabled. +When you add the `disabled` *attribute*, its presence alone initializes the button's `disabled` *property* to `true` +so the button is disabled. + +Adding and removing the `disabled` *attribute* disables and enables the button. The value of the *attribute* is irrelevant, +which is why you cannot enable a button by writing `<button disabled="false">Still Disabled</button>`. + +Setting the button's `disabled` *property* (say, with an Angular binding) disables or enables the button. +The value of the *property* matters. + +**The HTML attribute and the DOM property are not the same thing, even when they have the same name.** +This fact bears repeating: +**Template binding works with *properties* and *events*, not *attributes*.** + + +~~~ {.callout.is-helpful} + + +<header> + A world without attributes +</header> + +In the world of Angular, the only role of attributes is to initialize element and directive state. +When you write a data binding, you're dealing exclusively with properties and events of the target object. +HTML attributes effectively disappear. + +~~~ + +With this model firmly in mind, read on to learn about binding targets. + +### Binding targets +The **target of a data binding** is something in the DOM. +Depending on the binding type, the target can be an +(element | component | directive) property, an +(element | component | directive) event, or (rarely) an attribute name. +The following table summarizes: + +<style> + td, th {vertical-align: top} +</style> + + +<table width="100%"> + + <col width="10%"> + + </col> + + + <col width="15%"> + + </col> + + + <col width="75%"> + + </col> + + + <tr> + + <th> + Type + </th> + + + <th> + Target + </th> + + + <th> + Examples + </th> + + + </tr> + + + <tr> + + <td> + Property + </td> + + + <td> + Element property<br> + Component property<br> + Directive property + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-syntax-1'} + + + </td> + + + </tr> + + + <tr> + + <td> + Event + </td> + + + <td> + Element event<br> + Component event<br> + Directive event + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-syntax-1'} + + + </td> + + + </tr> + + + <tr> + + <td> + Two-way + </td> + + + <td> + Event and property + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='2-way-binding-syntax-1'} + + + </td> + + + </tr> + + + <tr> + + <td> + Attribute + </td> + + + <td> + Attribute + (the exception) + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='attribute-binding-syntax-1'} + + + </td> + + + </tr> + + + <tr> + + <td> + Class + </td> + + + <td> + <code>class</code> property + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='class-binding-syntax-1'} + + + </td> + + + </tr> + + + <tr> + + <td> + Style + </td> + + + <td> + <code>style</code> property + </td> + + + <td> + + + {@example 'template-syntax/ts/src/app/app.component.html' region='style-binding-syntax-1'} + + + </td> + + + </tr> + + +</table> + +</div>With this broad view in mind, you're ready to look at binding types in detail. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a property-binding} +## Property binding ( <span class="syntax">[property]</span> ) +Write a template **property binding** to set a property of a view element. +The binding sets the property to the value of a [template expression](#template-expressions). + +The most common property binding sets an element property to a component property value. An example is +binding the `src` property of an image element to a component's `heroImageUrl` property: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-1'} + +Another example is disabling a button when the component says that it `isUnchanged`: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-2'} + +Another is setting a property of a directive: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-3'} + +Yet another is setting the model property of a custom component (a great way +for parent and child components to communicate): + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-4'} + +### One-way *in* +People often describe property binding as *one-way data binding* because it flows a value in one direction, +from a component's data property into a target element property. + +You cannot use property binding to pull values *out* of the target element. +You can't bind to a property of the target element to _read_ it. You can only _set_ it. + +Similarly, you cannot use property binding to *call* a method on the target element. + +If the element raises events, you can listen to them with an [event binding](#event-binding). + +If you must read a target element property or call one of its methods, +you'll need a different technique. +See the API reference for +[ViewChild](../api/core/index/ViewChild-decorator.html) and +[ContentChild](../api/core/index/ContentChild-decorator.html). +### Binding target +An element property between enclosing square brackets identifies the target property. The target property in the following code is the image element's `src` property. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-1'} + +Some people prefer the `bind-` prefix alternative, known as the *canonical form*: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-5'} + +The target name is always the name of a property, even when it appears to be the name of something else. +You see `src` and may think it's the name of an attribute. No. It's the name of an image element property. + +Element properties may be the more common targets, +but Angular looks first to see if the name is a property of a known directive, +as it is in the following example: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-3'} + + +Technically, Angular is matching the name to a directive [input](#inputs-outputs), +one of the property names listed in the directive's `inputs` array or a property decorated with `@Input()`. +Such inputs map to the directive's own properties.If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error. + +### Avoid side effects +As mentioned previously, evaluation of a template expression should have no visible side effects. +The expression language itself does its part to keep you safe. +You can't assign a value to anything in a property binding expression nor use the increment and decrement operators. + +Of course, the expression might invoke a property or method that has side effects. +Angular has no way of knowing that or stopping you. + +The expression could call something like `getFoo()`. Only you know what `getFoo()` does. +If `getFoo()` changes something and you happen to be binding to that something, you risk an unpleasant experience. +Angular may or may not display the changed value. Angular may detect the change and throw a warning error. +In general, stick to data properties and to methods that return values and do no more. + +### Return the proper type +The template expression should evaluate to the type of value expected by the target property. +Return a string if the target property expects a string. +Return a number if the target property expects a number. +Return an object if the target property expects an object. + +The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-4'} + +### Remember the brackets +The brackets tell Angular to evaluate the template expression. +If you omit the brackets, Angular treats the string as a constant and *initializes the target property* with that string. +It does *not* evaluate the string! + +Don't make the following mistake: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-6'} + + + +{@a one-time-initialization} +### One-time string initialization +You *should* omit the brackets when all of the following are true: +* The target property accepts a string value. +* The string is a fixed value that you can bake into the template. +* This initial value never changes. + +You routinely initialize attributes this way in standard HTML, and it works +just as well for directive and component property initialization. +The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string, +not a template expression. Angular sets it and forgets about it. + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-7'} + +The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property. + +### Property binding or interpolation? +You often have a choice between interpolation and property binding. +The following binding pairs do the same thing: + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-vs-interpolation'} + +_Interpolation_ is a convenient alternative to _property binding_ in many cases. + +When rendering data values as strings, there is no technical reason to prefer one form to the other. +You lean toward readability, which tends to favor interpolation. +You suggest establishing coding style rules and choosing the form that +both conforms to the rules and feels most natural for the task at hand. + +When setting an element property to a non-string data value, you must use _property binding_. +#### Content security +Imagine the following *malicious content*. + +{@example 'template-syntax/ts/src/app/app.component.ts' region='evil-title'} + +Fortunately, Angular data binding is on alert for dangerous HTML. +It *sanitizes* the values before displaying them. +It **will not** allow HTML with script tags to leak into the browser, neither with interpolation +nor property binding. + +{@example 'template-syntax/ts/src/app/app.component.html' region='property-binding-vs-interpolation-sanitization'} + +Interpolation handles the script tags differently than property binding but both approaches render the +content harmlessly. +<figure class='image-display'> + <img src='/resources/images/devguide/template-syntax/evil-title.png' alt="evil title made safe" width='500px'> </img> +</figure> + + <a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a other-bindings} +## Attribute, class, and style bindings +The template syntax provides specialized one-way bindings for scenarios less well suited to property binding. + +### Attribute binding +You can set the value of an attribute directly with an **attribute binding**. +This is the only exception to the rule that a binding sets a target property. This is the only binding that creates and sets an attribute. +This guide stresses repeatedly that setting an element property with a property binding is always preferred to setting the attribute with a string. Why does Angular offer attribute binding? + +**You must use attribute binding when there is no element property to bind.** + +Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA), +[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG), and +table span attributes. They are pure attributes. +They do not correspond to element properties, and they do not set element properties. +There are no property targets to bind to. + +This fact becomes painfully obvious when you write something like this. +<code-example language="html"> + <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> +</code-example> + +And you get this error: +<code-example format="nocode"> + Template parse errors: + Can't bind to 'colspan' since it isn't a known native property +</code-example> + +As the message says, the `<td>` element does not have a `colspan` property. +It has the "colspan" *attribute*, but +interpolation and property binding can set only *properties*, not attributes. + +You need attribute bindings to create and bind to such attributes. + +Attribute binding syntax resembles property binding. +Instead of an element property between brackets, start with the prefix **`attr`**, +followed by a dot (`.`) and the name of the attribute. +You then set the attribute value, using an expression that resolves to a string. + +Bind `[attr.colspan]` to a calculated value: + +{@example 'template-syntax/ts/src/app/app.component.html' region='attrib-binding-colspan'} + +Here's how the table renders: +<table border="1px"> + <tr><td colspan="2">One-Two</td></tr> + <tr><td>Five</td><td>Six</td></tr> + </table> + +One of the primary use cases for attribute binding +is to set ARIA attributes, as in this example: + +{@example 'template-syntax/ts/src/app/app.component.html' region='attrib-binding-aria'} + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + +### Class binding + +You can add and remove CSS class names from an element's `class` attribute with +a **class binding**. + +Class binding syntax resembles property binding. +Instead of an element property between brackets, start with the prefix `class`, +optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-name]`. + +The following examples show how to add and remove the application's "special" class +with class bindings. Here's how to set the attribute without binding: + +{@example 'template-syntax/ts/src/app/app.component.html' region='class-binding-1'} + +You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding. + +{@example 'template-syntax/ts/src/app/app.component.html' region='class-binding-2'} + +Finally, you can bind to a specific class name. +Angular adds the class when the template expression evaluates to #{_truthy}. +It removes the class when the expression is #{_falsy}. + +{@example 'template-syntax/ts/src/app/app.component.html' region='class-binding-3'} + + +While this is a fine way to toggle a single class name, +the [NgClass directive](#ngClass) is usually preferred when managing multiple class names at the same time. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + +### Style binding + +You can set inline styles with a **style binding**. + +Style binding syntax resembles property binding. +Instead of an element property between brackets, start with the prefix `style`, +followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`. + + +{@example 'template-syntax/ts/src/app/app.component.html' region='style-binding-1'} + +Some style binding styles have a unit extension. +The following example conditionally sets the font size in “em” and “%” units . + +{@example 'template-syntax/ts/src/app/app.component.html' region='style-binding-2'} + + +While this is a fine way to set a single style, +the [NgStyle directive](#ngStyle) is generally preferred when setting several inline styles at the same time. + +Note that a _style property_ name can be written in either +[dash-case](glossary.html#dash-case), as shown above, or +[camelCase](glossary.html#camelcase), such as `fontSize`. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a event-binding} +## Event binding ( <span class="syntax">(event)</span> ) +The bindings directives you've met so far flow data in one direction: **from a component to an element**. + +Users don't just stare at the screen. They enter text into input boxes. They pick items from lists. +They click buttons. Such user actions may result in a flow of data in the opposite direction: +**from an element to a component**. + +The only way to know about a user action is to listen for certain events such as +keystrokes, mouse movements, clicks, and touches. +You declare your interest in user actions through Angular event binding. + +Event binding syntax consists of a **target event** within parentheses on the left of an equal sign, and a quoted +[template statement](#template-statements) on the right. +The following event binding listens for the button's click event, calling +the component's `onSave()` method whenever a click occurs: + +{@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-1'} + +### Target event +A **name between parentheses** — for example, `(click)` — +identifies the target event. In the following example, the target is the button's click event. + +{@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-1'} + +Some people prefer the `on-` prefix alternative, known as the **canonical form**: + +{@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-2'} + +Element events may be the more common targets, but Angular looks first to see if the name matches an event property +of a known directive, as it does in the following example: + +{@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-3'} + + +The `myClick` directive is further described in the section +on [aliasing input/output properties](#aliasing-io). +If the name fails to match an element event or an output property of a known directive, +Angular reports an “unknown directive” error. + +### *$event* and event handling statements +In an event binding, Angular sets up an event handler for the target event. + +When the event is raised, the handler executes the template statement. +The template statement typically involves a receiver, which performs an action +in response to the event, such as storing a value from the HTML control +into a model. + +The binding conveys information about the event, including data values, through +an **event object named `$event`**. + +The shape of the event object is determined by the target event. +If the target event is a native DOM element event, then `$event` is a +[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events), +with properties such as `target` and `target.value`. + +Consider this example: + +{@example 'template-syntax/ts/src/app/app.component.html' region='without-NgModel'} + +This code sets the input box `value` property by binding to the `name` property. To listen for changes to the value, the code binds to the input box's `input` event. +When the user makes changes, the `input` event is raised, and the binding executes the statement within a context that includes the DOM event object, `$event`. + +To update the `name` property, the changed text is retrieved by following the path `$event.target.value`. + +If the event belongs to a directive (recall that components are directives), `$event` has whatever shape the directive decides to produce. + + +{@a eventemitter} + + +{@a custom-event} +### Custom events with <span class="syntax">EventEmitter</span> + +Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html). +The directive creates an `EventEmitter` and exposes it as a property. +The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything. +Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object. + +Consider a `HeroDetailComponent` that presents hero information and responds to user actions. +Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself. +The best it can do is raise an event reporting the user's delete request. + +Here are the pertinent excerpts from that `HeroDetailComponent`:The component defines a `deleteRequest` property that returns an `EventEmitter`. +When the user clicks *delete*, the component invokes the `delete()` method, +telling the `EventEmitter` to emit a `Hero` object. + +Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event. +When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method, +passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable. + +### Template statements have side effects +The `deleteHero` method has a side effect: it deletes a hero. +Template statement side effects are not just OK, but expected. + +Deleting the hero updates the model, perhaps triggering other changes +including queries and saves to a remote server. +These changes percolate through the system and are ultimately displayed in this and other views. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a two-way} +## Two-way binding ( <span class="syntax">[(...)]</span> ) +You often want to both display a data property and update that property when the user makes changes. + +On the element side that takes a combination of setting a specific element property +and listening for an element change event. + +Angular offers a special _two-way data binding_ syntax for this purpose, **`[(x)]`**. +The `[(x)]` syntax combines the brackets +of _property binding_, `[x]`, with the parentheses of _event binding_, `(x)`. + + +~~~ {.callout.is-important} + + +<header> + [( )] = banana in a box +</header> + +Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets. + + +~~~ + +The `[(x)]` syntax is easy to demonstrate when the element has a settable property called `x` +and a corresponding event named `xChange`. +Here's a `SizerComponent` that fits the pattern. +It has a `size` value property and a companion `sizeChange` event: + + +{@example 'template-syntax/ts/src/app/sizer.component.ts'} + +The initial `size` is an input value from a property binding. +Clicking the buttons increases or decreases the `size`, within min/max values constraints, +and then raises (_emits_) the `sizeChange` event with the adjusted size. + +Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: +The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. +Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. +The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. +Try it in the <live-example></live-example>. + +The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. +Angular _desugars_ the `SizerComponent` binding into this: +The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. +Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. + +Clearly the two-way binding syntax is a great convenience compared to separate property and event bindings. + +It would be convenient to use two-way binding with HTML form elements like `<input>` and `<select>`. +However, no native HTML element follows the `x` value and `xChange` event pattern. + +Fortunately, the Angular [_NgModel_](#ngModel) directive is a bridge that enables two-way binding to form elements. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a directives} +## Built-in directives + +Earlier versions of Angular included over seventy built-in directives. +The community contributed many more, and countless private directives +have been created for internal applications. + +You don't need many of those directives in Angular. +You can often achieve the same results with the more capable and expressive Angular binding system. +Why create a directive to handle a click when you can write a simple binding such as this? + +{@example 'template-syntax/ts/src/app/app.component.html' region='event-binding-1'} + +You still benefit from directives that simplify complex tasks. +Angular still ships with built-in directives; just not as many. +You'll write your own directives, just not as many. + +This segment reviews some of the most frequently used built-in directives, +classified as either [_attribute_ directives](#attribute-directives) or [_structural_ directives](#structural-directives). + +<div class='l-hr'> + +</div> + + + +{@a attribute-directives} +## Built-in _attribute_ directives + +Attribute directives listen to and modify the behavior of +other HTML elements, attributes, properties, and components. +They are usually applied to elements as if they were HTML attributes, hence the name. + +Many details are covered in the [_Attribute Directives_](attribute-directives.html) guide. +Many Angular modules such the [`RouterModule`](router.html "Routing and Navigation") +and the [`FormsModule`](forms.html "Forms") have their own attribute directives. +This section is an introduction to the most commonly used attribute directives: + +* [`NgClass`](#ngClass) - add and remove a set of CSS classes +* [`NgStyle`](#ngStyle) - add and remove a set of HTML styles +* [`NgModel`](#ngModel) - two-way data binding to an HTML form element +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a ngClass} +### NgClass + +You typically control how elements appear +by adding and removing CSS classes dynamically. +You can bind to the `ngClass` to add or remove several classes simultaneously. + +A [class binding](#class-binding) is a good way to add or remove a *single* class. + +{@example 'template-syntax/ts/src/app/app.component.html' region='class-binding-3a'} + +To add or remove *many* CSS classes at the same time, the `NgClass` directive may be the better choice. + +Try binding `ngClass` to a key:value control !{__objectAsMap}. +Each key of the object is a CSS class name; its value is `true` if the class should be added, +`false` if it should be removed. +Consider a `setCurrentClasses` component method that sets a component property, +`currentClasses` with an object that adds or removes three classes based on the +`true`/`false` state of three other component properties: + +{@example 'template-syntax/ts/src/app/app.component.ts' region='setClasses'} + +Adding an `ngClass` property binding to `currentClasses` sets the element's classes accordingly: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgClass-1'} + + +It's up to you to call `setCurrentClassess()`, both initially and when the dependent properties change. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a ngStyle} +### NgStyle +You can set inline styles dynamically, based on the state of the component. +With `NgStyle` you can set many inline styles simultaneously. + +A [style binding](#style-binding) is an easy way to set a *single* style value. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgStyle-1'} + +To set *many* inline styles at the same time, the `NgStyle` directive may be the better choice. + +Try binding `ngStyle` to a key:value control !{__objectAsMap}. +Each key of the object is a style name; its value is whatever is appropriate for that style. + +Consider a `setCurrentStyles` component method that sets a component property, `currentStyles` +with an object that defines three styles, based on the state of three other component propertes: + +{@example 'template-syntax/ts/src/app/app.component.ts' region='setStyles'} + +Adding an `ngStyle` property binding to `currentStyles` sets the element's styles accordingly: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgStyle-2'} + + +It's up to you to call `setCurrentStyles()`, both initially and when the dependent properties change. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a ngModel} +### NgModel - Two-way binding to form elements with <span class="syntax">[(ngModel)]</span> +When developing data entry forms, you often both display a data property and +update that property when the user makes changes. + +Two-way data binding with the `NgModel` directive makes that easy. Here's an example:#### Inside <span class="syntax">[(ngModel)]</span> +Looking back at the `firstName` binding, note that +you could have achieved the same result with separate bindings to +the `<input>` element's `value` property and `input` event. + +{@example 'template-syntax/ts/src/app/app.component.html' region='without-NgModel'} + +That's cumbersome. Who can remember which element property to set and which element event emits user changes? +How do you extract the currently displayed text from the input box so you can update the data property? +Who wants to look that up each time? + +That `ngModel` directive hides these onerous details behind its own `ngModel` input and `ngModelChange` output properties. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgModel-3'} + + +The `ngModel` data property sets the element's value property and the `ngModelChange` event property +listens for changes to the element's value. + +The details are specific to each kind of element and therefore the `NgModel` directive only works for an element +supported by a [ControlValueAccessor](../api/forms/index/ControlValueAccessor-interface.html) +that adapts an element to this protocol. +The `<input>` box is one of those elements. +Angular provides *value accessors* for all of the basic HTML form elements and the +[_Forms_](forms.html) guide shows how to bind to them. + +You can't apply `[(ngModel)]` to a non-form native element or a third-party custom component until you write a suitable *value accessor*, +a technique that is beyond the scope of this guide. + +You don't need a _value accessor_ for an Angular component that you write because you can name the value and event properties +to suit Angular's basic [two-way binding syntax](#two-way) and skip `NgModel` altogether. +The [`sizer` shown above](#two-way) is an example of this technique. +Separate `ngModel` bindings is an improvement over binding to the element's native properties. You can do better. + +You shouldn't have to mention the data property twice. Angular should be able to capture the component's data property and set it +with a single declaration, which it can with the `[(ngModel)]` syntax: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgModel-1'} + +Is `[(ngModel)]` all you need? Is there ever a reason to fall back to its expanded form? + +The `[(ngModel)]` syntax can only _set_ a data-bound property. +If you need to do something more or something different, you can write the expanded form. + +The following contrived example forces the input value to uppercase: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgModel-4'} + +Here are all variations in action, including the uppercase version: +<figure class='image-display'> + <img src='/resources/images/devguide/template-syntax/ng-model-anim.gif' alt="NgModel variations"> </img> +</figure> + +  +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a structural-directives} +## Built-in _structural_ directives + +Structural directives are responsible for HTML layout. +They shape or reshape the DOM's _structure_, typically by adding, removing, and manipulating +the host elements to which they are attached. + +The deep details of structural directives are covered in the +[_Structural Directives_](structural-directives.html) guide +where you'll learn: +* why you +[_prefix the directive name with an asterisk_ (\*)](structural-directives.html#asterisk "The * in *ngIf"). +* to use [`<ng-container>`](structural-directives.html#ngcontainer "<ng-container>") +to group elements when there is no suitable host element for the directive. +* how to write your own structural directive. +* that you can only apply [one structural directive](structural-directives.html#one-per-element "one per host element") to an element. + +_This_ section is an introduction to the common structural directives: + +* [`NgIf`](#ngIf) - conditionally add or remove an element from the DOM +* [`NgFor`](#ngFor) - repeat a template for each item in a list +* [`NgSwitch`](#ngSwitch) - a set of directives that switch among alternative views + +<div class='l-hr'> + +</div> + + + +{@a ngIf} +### NgIf +You can add or remove an element from the DOM by applying an `NgIf` directive to +that element (called the _host elment_). +Bind the directive to a condition expression like `isActive` in this example. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgIf-1'} + + + +~~~ {.alert.is-critical} + +Don't forget the asterisk (`*`) in front of `ngIf`. + +~~~ + +When the `isActive` expression returns a #{_truthy} value, `NgIf` adds the `HeroDetailComponent` to the DOM. +When the expression is #{_falsy}, `NgIf` removes the `HeroDetailComponent` +from the DOM, destroying that component and all of its sub-components. +#### Show/hide is not the same thing +You can control the visibility of an element with a +[class](#class-binding) or [style](#style-binding) binding: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgIf-3'} + +Hiding an element is quite different from removing an element with `NgIf`. + +When you hide an element, that element and all of its descendents remain in the DOM. +All components for those elements stay in memory and +Angular may continue to check for changes. +You could be holding onto considerable computing resources and degrading performance, +for something the user can't see. + +When `NgIf` is `false`, Angular physically removes the element and its descendents from the DOM. +It destroys their components, potentially freeing up substantial resources, +resulting in a more responsive user experience. + +The show/hide technique is fine for a few elements with few children. +You should be wary when hiding large component trees; `NgIf` may be the safer choice. + +#### Guard against null objects +The `ngIf` directive is often used to guard against a null object. +Show/hide is useless as a guard. +Angular will throw an error if a nested expression tries to access a property of a null object, +whether its visible or not. + +Here we see `NgIf` guarding two `<div>`s. +The `currentHero` name will appear only when there is a `currentHero`. +The `nullHero` will never be displayed. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgIf-2'} + + +See also the +[_safe navigation operator_](#safe-navigation-operator "Safe naviation operator (?.)") +described below. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a ngFor} +### NgFor +`NgFor` is a _repeater_ directive — a way to present a list of items. +You define a block of HTML that defines how a single item should be displayed. +You tell Angular to use that block as a template for rendering each item in the list. + +Here is an example of `NgFor` applied to a simple `<div>`: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgFor-1'} + +You can also apply an `NgFor` to a component element, as in this example: + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgFor-2'} + + + +~~~ {.alert.is-critical} + +Don't forget the asterisk (`*`) in front of `ngFor`. + +~~~ + +The text assigned to `*ngFor` is the instruction that guides the repeater process. + + +{@a microsyntax} +#### *ngFor microsyntax +The string assigned to `*ngFor` is not a [template expression](#template-expressions). +It's a *microsyntax* — a little language of its own that Angular interprets. +The string `"let hero of heroes"` means: + +> *Take each hero in the `heroes` #{_array}, store it in the local `hero` looping variable, and +make it available to the templated HTML for each iteration.* + +Angular translates this instruction into a `<template>` around the host element, +then uses this template repeatedly to create a new set of elements and bindings for each `hero` +in the list. +Learn about the _microsyntax_ in the [_Structural Directives_](structural-directives.html#microsyntax) guide. + + +{@a template-input-variable} + + +{@a template-input-variables} +### Template input variables + +The `let` keyword before `hero` creates a _template input variable_ called `hero`. +The `ngFor` directive iterates over the `heroes` #{_array} returned by the parent component's `heroes` property +and sets the `hero` element with the current item from the #{_array} during each iteration. + +You reference the `hero` input variable within the `ngFor` host element (and within its descendents) to access the hero's properties. +Here it is referenced first in an interpolation +and then passed in a binding to the `hero` property of the `<hero-detail>` component. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgFor-1-2'} + +Learn more about _template input variables_ in the [_Structural Directives_](structural-directives.html#template-input-variable) guide. + +#### *ngFor with _index_ +The `index` property of the `NgFor` directive context returns the zero-based index of the item in each iteration. +You can capture the `index` in a template input variable and use it in the template. + +The next example captures the `index` in a variable named `i` and displays it with the hero name like this. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgFor-3'} + + +Learn about the other `NgFor` context values such as `last`, `even`, and `odd` in the [NgFor API reference](../api/common/index/NgFor-directive.html). + + +{@a trackBy} +#### *ngFor with _trackBy_ +The `NgFor` directive may perform poorly, especially with large lists. +A small change to one item, an item removed, or an item added can trigger a cascade of DOM manipulations. + +For example, re-querying the server could reset the list with all new hero objects. + +Most, if not all, are previously displayed heroes. +*You* know this because the `id` of each hero hasn't changed. +But Angular sees only a fresh list of new object references. +It has no choice but to tear down the old DOM elements and insert all new DOM elements. + +Angular can avoid this churn with `trackBy`. +Add a method to the component that returns the value `NgFor` _should_ track. +In this case, that value is the hero's `id`. + +{@example 'template-syntax/ts/src/app/app.component.ts' region='trackByHeroes'} + +In the microsyntax expression, set `trackBy` to this method. + +{@example 'template-syntax/ts/src/app/app.component.html' region='trackBy'} + +Here is an illustration of the _trackBy_ effect. +"Reset heroes" creates new heroes with the same `hero.id`s. +"Change ids" creates new heroes with new `hero.id`s. +* With no `trackBy`, both buttons trigger complete DOM element replacement. +* With `trackBy`, only changing the `id` triggers element replacement. + +<figure class='image-display'> + <img src='/resources/images/devguide/template-syntax/ng-for-track-by-anim.gif' alt="trackBy"> </img> +</figure> + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a ngSwitch} +### The _NgSwitch_ directives + +*NgSwitch* is like the JavaScript `switch` statement. +It can display _one_ element from among several possible elements, based on a _switch condition_. +Angular puts only the *selected* element into the DOM. + +*NgSwitch* is actually a set of three, cooperating directives: +`NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault` as seen in this example. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgSwitch'} + + +<figure class='image-display'> + <img src='/resources/images/devguide/template-syntax/switch-anim.gif' alt="trackBy"> </img> +</figure> + +`NgSwitch` is the controller directive. Bind it to an expression that returns the *switch value*. +The `emotion` value in this example is a string, but the switch value can be of any type. + +**Bind to `[ngSwitch]`**. You'll get an error if you try to set `*ngSwitch`. +`NgSwitch` is an *attribute* directive, not a *structural* directive. +It changes the behavior of its companion directives. +It doesn't touch the DOM directly. + +**Bind to `*ngSwitchCase` and `*ngSwitchDefault`**. +The `NgSwitchCase` and `NgSwitchDefault` directives are _structural_ directives +because they add or remove elements from the DOM. + +* `NgSwitchCase` adds its element to the DOM when its bound value equals the switch value. + +* `NgSwitchDefault` adds its element to the DOM when there is no selected `NgSwitchCase`. + +The switch directives are particularly useful for adding and removing *component elements*. +This example switches among four "emotional hero" components defined in the `hero-switch.components.ts` file. +Each component has a `hero` [input property](#inputs-outputs "Input property") +which is bound to the `currentHero` of the parent component. + +Switch directives work as well with native elements and web components too. +For example, you could replace the `<confused-hero>` switch case with the following. + +{@example 'template-syntax/ts/src/app/app.component.html' region='NgSwitch-div'} + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a template-reference-variable} + + +{@a ref-vars} + + +{@a ref-var} +## Template reference variables ( <span class="syntax">#var</span> ) +A **template reference variable** is often a reference to a DOM element within a template. +It can also be a reference to an Angular component or directive or a +<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" target="_blank" title="MDN: Web Components">web component</a>. + +Use the hash symbol (#) to declare a reference variable. +The `#phone` declares a `phone` variable on an `<input>` element. + +{@example 'template-syntax/ts/src/app/app.component.html' region='ref-var'} + +You can refer to a template reference variable _anywhere_ in the template. +The `phone` variable declared on this `<input>` is +consumed in a `<button>` on the other side of the template + +{@example 'template-syntax/ts/src/app/app.component.html' region='ref-phone'} + +### How a reference variable gets its value + +In most cases, Angular sets the reference variable's value to the element on which it was declared. +In the previous example, `phone` refers to the _phone number_ `<input>` box. +The phone button click handler passes the _input_ value to the component's `callPhone` method. +But a directive can change that behavior and set the value to something else, such as itself. +The `NgForm` directive does that. + +The following is a *simplified* version of the form example in the [Forms](forms.html) guide. + +{@example 'template-syntax/ts/src/app/hero-form.component.html'} + +A template reference variable, `heroForm`, appears three times in this example, separated +by a large amount of HTML. +What is the value of `heroForm`? + +If Angular hadn't taken it over when you imported the `FormsModule`, +it would be the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement). +The `heroForm` is actually a reference to an Angular [NgForm](../api/forms/index/NgForm-directive.html "API: NgForm") +directive with the ability to track the value and validity of every control in the form. + +The native `<form>` element doesn't have a `form` property. +But the `NgForm` directive does, which explains how you can disable the submit button +if the `heroForm.form.valid` is invalid and pass the entire form control tree +to the parent component's `onSubmit` method. + +### Template reference variable warning notes + +A template _reference_ variable (`#phone`) is _not_ the same as a template _input_ variable (`let phone`) +such as you might see in an [`*ngFor`](#template-input-variable). +Learn the difference in the [_Structural Directives_](structural-directives.html#template-input-variable) guide. + +The scope of a reference variable is the _entire template_. +Do not define the same variable name more than once in the same template. +The runtime value will be unpredictable. + +You can use the `ref-` prefix alternative to `#`. +This example declares the `fax` variable as `ref-fax` instead of `#fax`. + +{@example 'template-syntax/ts/src/app/app.component.html' region='ref-fax'} + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a inputs-outputs} +## Input and output properties ( <span class="syntax">@Input</span> and <span class="syntax">@Output</span> ) +So far, you've focused mainly on binding to component members within template expressions and statements +that appear on the *right side of the binding declaration*. +A member in that position is a data binding **source**. + +This section concentrates on binding to **targets**, which are directive +properties on the *left side of the binding declaration*. +These directive properties must be declared as **inputs** or **outputs**. + + +~~~ {.alert.is-important} + +Remember: All **components** are **directives**. + +~~~ + + +You're drawing a sharp distinction between a data binding **target** and a data binding **source**. + +The *target* of a binding is to the *left* of the `=`. +The *source* is on the *right* of the `=`. + +The *target* of a binding is the property or event inside the binding punctuation: `[]`, `()` or `[()]`. +The *source* is either inside quotes (`" "`) or within an interpolation (`{{}}`). + +Every member of a **source** directive is automatically available for binding. +You don't have to do anything special to access a directive member in a template expression or statement. + +You have *limited* access to members of a **target** directive. +You can only bind to properties that are explicitly identified as *inputs* and *outputs*.In the following snippet, `iconUrl` and `onSave` are data-bound members of the `AppComponent` +and are referenced within quoted syntax to the _right_ of the equals (`=`). + +{@example 'template-syntax/ts/src/app/app.component.html' region='io-1'} + +They are *neither inputs nor outputs* of the component. They are **sources** for their bindings. +The targets are the native `<img>` and `<button>` elements. + +Now look at a another snippet in which the `HeroDetailComponent` is the **target** of a binding on the _left_ of the equals (`=`). + +{@example 'template-syntax/ts/src/app/app.component.html' region='io-2'} + +Both `HeroDetailComponent.hero` and `HeroDetailComponent.deleteRequest` are on the **left side** of binding declarations. +`HeroDetailComponent.hero` is inside brackets; it is the target of a property binding. +`HeroDetailComponent.deleteRequest` is inside parentheses; it is the target of an event binding. + +### Declaring input and output properties +Target properties must be explicitly marked as inputs or outputs. + +In the `HeroDetailComponent`, such properties are marked with decorators as input and output properties. + +{@example 'template-syntax/ts/src/app/hero-detail.component.ts' region='input-output-1'} + + +Alternatively, you can identify members in the `inputs` and `outputs` #{_array}s +of the directive metadata, as in this example: + +{@example 'template-syntax/ts/src/app/hero-detail.component.ts' region='input-output-2'} + +<br>You can specify an input/output property either with a decorator or in a metadata #{_array}. +Don't do both!### Input or output? + +*Input* properties usually receive data values. +*Output* properties expose event producers, such as `EventEmitter` objects. + +The terms _input_ and _output_ reflect the perspective of the target directive. +<figure class='image-display'> + <img src='/resources/images/devguide/template-syntax/input-output.png' alt="Inputs and outputs"> </img> +</figure> + +`HeroDetailComponent.hero` is an **input** property from the perspective of `HeroDetailComponent` +because data flows *into* that property from a template binding expression. + +`HeroDetailComponent.deleteRequest` is an **output** property from the perspective of `HeroDetailComponent` +because events stream *out* of that property and toward the handler in a template binding statement. + +<h3 id='aliasing-io'> + Aliasing input/output properties +</h3> + +Sometimes the public name of an input/output property should be different from the internal name. + +This is frequently the case with [attribute directives](attribute-directives.html). +Directive consumers expect to bind to the name of the directive. +For example, when you apply a directive with a `myClick` selector to a `<div>` tag, +you expect to bind to an event property that is also called `myClick`. + +{@example 'template-syntax/ts/src/app/app.component.html' region='myClick'} + +However, the directive name is often a poor choice for the name of a property within the directive class. +The directive name rarely describes what the property does. +The `myClick` directive name is not a good name for a property that emits click messages. + +Fortunately, you can have a public name for the property that meets conventional expectations, +while using a different name internally. +In the example immediately above, you are actually binding *through the* `myClick` *alias* to +the directive's own `clicks` property. + +You can specify the alias for the property name by passing it into the input/output decorator like this: + + +{@example 'template-syntax/ts/src/app/click.directive.ts' region='output-myClick'} + + +You can also alias property names in the `inputs` and `outputs` #{_array}s. +You write a colon-delimited (`:`) string with +the directive property name on the *left* and the public alias on the *right*: + +{@example 'template-syntax/ts/src/app/click.directive.ts' region='output-myClick2'} + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a expression-operators} +## Template expression operators +The template expression language employs a subset of #{_JavaScript} syntax supplemented with a few special operators +for specific scenarios. The next sections cover two of these operators: _pipe_ and _safe navigation operator_. + + +{@a pipe} +### The pipe operator ( <span class="syntax">|</span> ) +The result of an expression might require some transformation before you're ready to use it in a binding. +For example, you might display a number as a currency, force text to uppercase, or filter a list and sort it. + +Angular [pipes](./pipes.html) are a good choice for small transformations such as these. +Pipes are simple functions that accept an input value and return a transformed value. +They're easy to apply within template expressions, using the **pipe operator (`|`)**: + +{@example 'template-syntax/ts/src/app/app.component.html' region='pipes-1'} + +The pipe operator passes the result of an expression on the left to a pipe function on the right. + +You can chain expressions through multiple pipes: + +{@example 'template-syntax/ts/src/app/app.component.html' region='pipes-2'} + +And you can also [apply parameters](./pipes.html#parameterizing-a-pipe) to a pipe: + +{@example 'template-syntax/ts/src/app/app.component.html' region='pipes-3'} + +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + + + +{@a safe-navigation-operator} +### The safe navigation operator ( <span class="syntax">?.</span> ) and null property paths + +The Angular **safe navigation operator (`?.`)** is a fluent and convenient way to guard against null and undefined values in property paths. +Here it is, protecting against a view render failure if the `currentHero` is null. + +{@example 'template-syntax/ts/src/app/app.component.html' region='safe-2'} + +What happens when the following data bound `title` property is null? + +{@example 'template-syntax/ts/src/app/app.component.html' region='safe-1'} + +The view still renders but the displayed value is blank; you see only "The title is" with nothing after it. +That is reasonable behavior. At least the app doesn't crash. + +Suppose the template expression involves a property path, as in this next example +that displays the `firstName` of a null hero. + +<code-example language="html"> + The null hero's name is {{nullHero.firstName}} + +</code-example> + +Worse, the *entire view disappears*. + +This would be reasonable behavior if the `hero` property could never be null. +If it must never be null and yet it is null, +that's a programming error that should be caught and fixed. +Throwing an exception is the right thing to do. + +On the other hand, null values in the property path may be OK from time to time, +especially when the data are null now and will arrive eventually. + +While waiting for data, the view should render without complaint, and +the null property path should display as blank just as the `title` property does. + +Unfortunately, the app crashes when the `currentHero` is null. + +You could code around that problem with [*ngIf](#ngIf). + +{@example 'template-syntax/ts/src/app/app.component.html' region='safe-4'} + +These approaches have merit but can be cumbersome, especially if the property path is long. +Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`. + +The Angular safe navigation operator (`?.`) is a more fluent and convenient way to guard against nulls in property paths. +The expression bails out when it hits the first null value. +The display is blank, but the app keeps rolling without errors. + +{@example 'template-syntax/ts/src/app/app.component.html' region='safe-6'} + +It works perfectly with long property paths such as `a?.b?.c?.d`. +<a href="#toc">back to top</a> +<div class='l-hr'> + +</div> + +## Summary +You've completed this survey of template syntax. +Now it's time to put that knowledge to work on your own components and directives. \ No newline at end of file diff --git a/aio/content/guide/upgrade.md b/aio/content/guide/upgrade.md new file mode 100644 index 0000000000..88c1d547e4 --- /dev/null +++ b/aio/content/guide/upgrade.md @@ -0,0 +1,2191 @@ +@title +Upgrading from AngularJS + +@intro +Incrementally upgrade an AngularJS application to Angular. + +@description +_Angular_ is the name for the Angular of today and tomorrow. +_AngularJS_ is the name for all v1.x versions of Angular. + +AngularJS apps are great. +Always consider the business case before moving to Angular. +An important part of that case is the time and effort to get there. +This guide describes the built-in tools for efficiently migrating AngularJS projects over to the +Angular platform, a piece at a time. + +Some applications will be easier to upgrade than others, and there are +ways in which we can make it easier for ourselves. It is possible to +prepare and align AngularJS applications with Angular even before beginning +the upgrade process. These preparation steps are all about making the code +more decoupled, more maintainable, and up to speed with modern development +tools. That means the preparation work will not only make the eventual upgrade +easier, but will also generally improve our AngularJS applications. + +One of the keys to a successful upgrade is to do it incrementally, +by running the two frameworks side by side in the same application, and +porting AngularJS components to Angular one by one. This makes it possible +to upgrade even large and complex applications without disrupting other +business, because the work can be done collaboratively and spread over +a period of time. The `upgrade` module in Angular has been designed to +make incremental upgrading seamless. + +1. [Preparation](#preparation) + 1. [Follow the Angular Style Guide](#follow-the-angular-style-guide) + 2. [Using a Module Loader](#using-a-module-loader) + 3. [Migrating to TypeScript](#migrating-to-typescript) + 4. [Using Component Directives](#using-component-directives) +2. [Upgrading with The Upgrade Module](#upgrading-with-the-upgrade-module) + 1. [How The Upgrade Module Works](#how-the-upgrade-module-works) + 2. [Bootstrapping hybrid](#bootstrapping-hybrid-applications) + 3. [Using Angular Components from AngularJS Code](#using-angular-components-from-angularjs-code) + 4. [Using AngularJS Component Directives from Angular Code](#using-angularjs-component-directives-from-angular-code) + 5. [Projecting AngularJS Content into Angular Components](#projecting-angularjs-content-into-angular-components) + 6. [Transcluding Angular Content into AngularJS Component Directives](#transcluding-angular-content-into-angularjs-component-directives) + 7. [Making AngularJS Dependencies Injectable to Angular](#making-angularjs-dependencies-injectable-to-angular) + 8. [Making Angular Dependencies Injectable to AngularJS](#making-angular-dependencies-injectable-to-angularjs) + 9. [Using Ahead-of-time compilation with hybrid apps](#using-ahead-of-time-compilation-with-hybrid-apps) + 10. [Dividing routes between Angular and AngularJS](#dividing-routes-between-angular-and-angularjs) +3. [PhoneCat Upgrade Tutorial](#phonecat-upgrade-tutorial) + 1. [Switching to TypeScript](#switching-to-typescript) + 2. [Installing Angular](#installing-angular) + 3. [Bootstrapping a hybrid PhoneCat](#bootstrapping-a-hybrid-phonecat) + 4. [Upgrading the Phone service](#upgrading-the-phone-service) + 5. [Upgrading Components](#upgrading-components) + 6. [AoT compile the hybrid app](#aot-compile-the-hybrid-app) + 7. [Adding The Angular Router And Bootstrap](#adding-the-angular-router-and-bootstrap) + 8. [Say Goodbye to AngularJS](#say-goodbye-to-angularjs) +3. [Appendix: Upgrading PhoneCat Tests](#appendix-upgrading-phonecat-tests) + +## Preparation + +There are many ways to structure AngularJS applications. When we begin +to upgrade these applications to Angular, some will turn out to be +much more easy to work with than others. There are a few key techniques +and patterns that we can apply to future proof our apps even before we +begin the migration. + +### Follow the Angular Style Guide + +The [AngularJS Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) +collects patterns and practices that have been proven to result in +cleaner and more maintainable AngularJS applications. It contains a wealth +of information about how to write and organize Angular code - and equally +importantly - how **not** to write and organize Angular code. + +Angular is a reimagined version of the best parts of AngularJS. In that +sense, its goals are the same as the Angular Style Guide's: To preserve +the good parts of AngularJS, and to avoid the bad parts. There's a lot +more to Angular than just that of course, but this does mean that +*following the style guide helps make your AngularJS app more closely +aligned with Angular*. + +There are a few rules in particular that will make it much easier to do +*an incremental upgrade* using the Angular `upgrade` module: + +* The [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility) + states that there should be one component per file. This not only makes + components easy to navigate and find, but will also allow us to migrate + them between languages and frameworks one at a time. In this example application, + each controller, component, service, and filter is in its own source file. + +* The [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#folders-by-feature-structure) + and [Modularity](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity) + rules define similar principles on a higher level of abstraction: Different parts of the + application should reside in different directories and Angular modules. + +When an application is laid out feature per feature in this way, it can also be +migrated one feature at a time. For applications that don't already look like +this, applying the rules in the Angular style guide is a highly recommended +preparation step. And this is not just for the sake of the upgrade - it is just +solid advice in general! + +### Using a Module Loader + +When we break application code down into one component per file, we often end +up with a project structure with a large number of relatively small files. This is +a much neater way to organize things than a small number of large files, but it +doesn't work that well if you have to load all those files to the HTML page with +<script> tags. Especially when you also have to maintain those tags in the correct +order. That's why it's a good idea to start using a *module loader*. + +Using a module loader such as [SystemJS](https://github.com/systemjs/systemjs), +[Webpack](http://webpack.github.io/), or [Browserify](http://browserify.org/) +allows us to use the built-in module systems of the TypeScript or ES2015 languages in our apps. +We can use the `import` and `export` features that explicitly specify what code can +and will be shared between different parts of the application. For ES5 applications +we can use CommonJS style `require` and `module.exports` features. In both cases, +the module loader will then take care of loading all the code the application needs +in the correct order. + +When we then take our applications into production, module loaders also make it easier +to package them all up into production bundles with batteries included. +### Migrating to TypeScript + +If part of our Angular upgrade plan is to also take TypeScript into use, it makes +sense to bring in the TypeScript compiler even before the upgrade itself begins. +This means there's one less thing to learn and think about during the actual upgrade. +It also means we can start using TypeScript features in our AngularJS code. + +Since TypeScript is a superset of ECMAScript 2015, which in turn is a superset +of ECMAScript 5, "switching" to TypeScript doesn't necessarily require anything +more than installing the TypeScript compiler and switching renaming files from +`*.js` to `*.ts`. But just doing that is not hugely useful or exciting, of course. +Additional steps like the following can give us much more bang for the buck: + +* For applications that use a module loader, TypeScript imports and exports + (which are really ECMAScript 2015 imports and exports) can be used to organize + code into modules. +* Type annotations can be gradually added to existing functions and variables + to pin down their types and get benefits like build-time error checking, + great autocompletion support and inline documentation. +* JavaScript features new to ES2015, like arrow functions, `let`s and `const`s, + default function parameters, and destructuring assignments can also be gradually + added to make the code more expressive. +* Services and controllers can be turned into *classes*. That way they'll be a step + closer to becoming Angular service and component classes, which will make our + life easier once we do the upgrade. + +### Using Component Directives + +In Angular, components are the main primitive from which user interfaces +are built. We define the different parts of our UIs as components, and then +compose the UI by using components in our templates. + +You can also do this in AngularJS, using *component directives*. These are +directives that define their own templates, controllers, and input/output bindings - +the same things that Angular components define. Applications built with +component directives are much easier to migrate to Angular than applications +built with lower-level features like `ng-controller`, `ng-include`, and scope +inheritance. + +To be Angular compatible, an AngularJS component directive should configure +these attributes: + +* `restrict: 'E'`. Components are usually used as elements. +* `scope: {}` - an isolate scope. In Angular, components are always isolated + from their surroundings, and we should do this in AngularJS too. +* `bindToController: {}`. Component inputs and outputs should be bound + to the controller instead of using the `$scope`. +* `controller` and `controllerAs`. Components have their own controllers. +* `template` or `templateUrl`. Components have their own templates. + +Component directives may also use the following attributes: + +* `transclude: true`, if the component needs to transclude content from elsewhere. +* `require`, if the component needs to communicate with some parent component's + controller. + +Component directives **may not** use the following attributes: + +* `compile`. This will not be supported in Angular. +* `replace: true`. Angular never replaces a component element with the + component template. This attribute is also deprecated in AngularJS. +* `priority` and `terminal`. While AngularJS components may use these, + they are not used in Angular and it is better not to write code + that relies on them. + +An AngularJS component directive that is fully aligned with the Angular +architecture may look something like this: + + +{@example 'upgrade-module/ts/src/app/hero-detail.directive.ts'} + +AngularJS 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module) +that makes it easier to define directives like these. It is a good idea to use +this API for component directives for several reasons: + +* It requires less boilerplate code. +* It enforces the use of component best practices like `controllerAs`. +* It has good default values for directive attributes like `scope` and `restrict`. + +The component directive example from above looks like this when expressed +using the component API: + + +{@example 'upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts'} + +Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()` +are another convenient feature that AngularJS 1.5 introduces. They all have nearly +exact [equivalents in Angular](lifecycle-hooks.html), so organizing component lifecycle +logic around them will ease the eventual Angular upgrade process. + +## Upgrading with The Upgrade Module + +The `upgrade` module in Angular is a very useful tool for upgrading +anything but the smallest of applications. With it we can mix and match +AngularJS and Angular components in the same application and have them interoperate +seamlessly. That means we don't have to do the upgrade work all at once, +since there's a natural coexistence between the two frameworks during the +transition period. + +### How The Upgrade Module Works + +The primary tool provided by the upgrade module is called the `UpgradeModule`. +This is a service that can bootstrap and manage hybrid applications that support +both Angular and AngularJS code. + +When we use `UpgradeModule`, what we're really doing is *running both versions +of Angular at the same time*. All Angular code is running in the Angular +framework, and AngularJS code in the AngularJS framework. Both of these are the +actual, fully featured versions of the frameworks. There is no emulation going on, +so we can expect to have all the features and natural behavior of both frameworks. + +What happens on top of this is that components and services managed by one +framework can interoperate with those from the other framework. This happens +in three main areas: Dependency injection, the DOM, and change detection. + +#### Dependency Injection + +Dependency injection is front and center in both AngularJS and +Angular, but there are some key differences between the two +frameworks in how it actually works. + +<table> + + <tr> + + <th> + AngularJS + </th> + + + <th> + Angular + </th> + + + </tr> + + + <tr> + + <td> + Dependency injection tokens are always strings + </td> + + + <td> + Tokens [can have different types](../guide/dependency-injection.html). + They are often classes. They may also be strings. + </td> + + + </tr> + + + <tr> + + <td> + There is exactly one injector. Even in multi-module applications, + everything is poured into one big namespace. + </td> + + + <td> + There is a [tree hierarchy of injectors](../guide/hierarchical-dependency-injection.html), + with a root injector and an additional injector for each component. + + </td> + + + </tr> + + +</table> + +Even accounting for these differences we can still have dependency injection +interoperability. The `UpgradeModule` resolves the differences and makes +everything work seamlessly: + +* We can make AngularJS services available for injection to Angular code + by *upgrading* them. The same singleton instance of each service is shared + between the frameworks. In Angular these services will always be in the + *root injector* and available to all components. +* We can also make Angular services available for injection to AngularJS code + by *downgrading* them. Only services from the Angular root injector can + be downgraded. Again, the same singleton instances are shared between the frameworks. + When we register a downgrade, we explicitly specify a *string token* that we want to + use in AngularJS. + +<figure class='image-display'> + <img src="/resources/images/devguide/upgrade/injectors.png" alt="The two injectors in a hybrid application" width="700"> </img> +</figure> + +#### Components and the DOM + +What we'll find in the DOM of a hybrid application are components and +directives from both AngularJS and Angular. These components +communicate with each other by using the input and output bindings +of their respective frameworks, which the `UpgradeModule` bridges +together. They may also communicate through shared injected dependencies, +as described above. + +There are two key things to understand about what happens in the DOM +of a hybrid application: + +1. Every element in the DOM is owned by exactly one of the two + frameworks. The other framework ignores it. If an element is + owned by AngularJS, Angular treats it as if it didn't exist, + and vice versa. +2. The root of the application *is always an AngularJS template*. + +So a hybrid application begins life as an AngularJS application, +and it is AngularJS that processes its root template. Angular then steps +into the picture when an Angular component is used somewhere in +the application templates. That component's view will then be managed +by Angular, and it may use any number of Angular components and +directives. + +Beyond that, we may interleave the two frameworks as much as we need to. +We always cross the boundary between the two frameworks by one of two +ways: + +1. By using a component from the other framework: An AngularJS template + using an Angular component, or an Angular template using an + AngularJS component. +2. By transcluding or projecting content from the other framework. The + `UpgradeModule` bridges the related concepts of AngularJS transclusion + and Angular content projection together. + +<figure class='image-display'> + <img src="/resources/images/devguide/upgrade/dom.png" alt="DOM element ownership in a hybrid application" width="500"> </img> +</figure> + +Whenever we use a component that belongs to the other framework, a +switch between framework boundaries occurs. However, that switch only +happens to the *children* of the component element. Consider a situation +where we use an Angular component from AngularJS like this: + +<code-example language="html" escape="html"> + <a-component></a-component> + +</code-example> + +The DOM element `<a-component>` will remain to be an AngularJS managed +element, because it's defined in an AngularJS template. That also +means you can apply additional AngularJS directives to it, but *not* +Angular directives. It is only in the template of the `<a-component>` +where Angular steps in. This same rule also applies when you +use AngularJS component directives from Angular. +#### Change Detection + +Change detection in AngularJS is all about `scope.$apply()`. After every +event that occurs, `scope.$apply()` gets called. This is done either +automatically by the framework, or in some cases manually by our own +code. It is the point in time when change detection occurs and data +bindings get updated. + +In Angular things are different. While change detection still +occurs after every event, no one needs to call `scope.$apply()` for +that to happen. This is because all Angular code runs inside something +called the [Angular zone](../api/core/index/NgZone-class.html). Angular always +knows when the code finishes, so it also knows when it should kick off +change detection. The code itself doesn't have to call `scope.$apply()` +or anything like it. + +In the case of hybrid applications, the `UpgradeModule` bridges the +AngularJS and Angular approaches. Here's what happens: + +* Everything that happens in the application runs inside the Angular zone. + This is true whether the event originated in AngularJS or Angular code. + The zone triggers Angular change detection after every event. +* The `UpgradeModule` will invoke the AngularJS `$rootScope.$apply()` after + every turn of the Angular zone. This also triggers AngularJS change + detection after every event. + +<figure class='image-display'> + <img src="/resources/images/devguide/upgrade/change_detection.png" alt="Change detection in a hybrid application" width="600"> </img> +</figure> + +What this means in practice is that we do not need to call `$apply()` in +our code, regardless of whether it is in AngularJS on Angular. The +`UpgradeModule` does it for us. We *can* still call `$apply()` so there +is no need to remove such calls from existing code. Those calls just don't +have any effect in a hybrid application. + +When we downgrade an Angular component and then use it from AngularJS, +the component's inputs will be watched using AngularJS change detection. +When those inputs change, the corresponding properties in the component +are set. We can also hook into the changes by implementing the +[OnChanges](../api/core/index/OnChanges-class.html) interface in the component, +just like we could if it hadn't been downgraded. + +Correspondingly, when we upgrade an AngularJS component and use it from Angular, +all the bindings defined for the component directive's `scope` (or `bindToController`) +will be hooked into Angular change detection. They will be treated +as regular Angular inputs and set onto the scope (or controller) when +they change. + +### Using UpgradeModule with Angular _NgModules_ + +Both AngularJS and Angular have their own concept of modules +to help organize an application into cohesive blocks of functionality. + +Their details are quite different in architecture and implementation. +In AngularJS, you add Angular assets to the `angular.module` property. +In Angular, you create one or more classes adorned with an `NgModule` decorator +that describes Angular assets in metadata. The differences blossom from there. + +In a hybrid application we run both versions of Angular at the same time. +That means that we need at least one module each from both AngularJS and Angular. +We will import `UpgradeModule` inside our Angular module, and then use it for +bootstrapping our AngularJS module. Let's see how. + +Learn more about Angular modules at the [NgModule guide](ngmodule.html). +### Bootstrapping hybrid applications + +The first step to upgrading an application using the `UpgradeModule` is +always to bootstrap it as a hybrid that supports both AngularJS and +Angular, but still is an AngularJS app at top level. + +Pure AngularJS applications can be bootstrapped in two ways: By using an `ng-app` +directive somewhere on the HTML page, or by calling +[angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap) +from JavaScript. In Angular, only the second method is possible - there is +no `ng-app` in Angular. This is also the case for hybrid applications. +Therefore, it is a good preliminary step to switch AngularJS applications to use the +JavaScript bootstrap method even before switching them to hybrid mode. + +Say we have an `ng-app` driven bootstrap such as this one: + + +{@example 'upgrade-module/ts/src/index-ng-app.html'} + +We can remove the `ng-app` and `ng-strict-di` directives from the HTML +and instead switch to calling `angular.bootstrap` from JavaScript, which +will result in the same thing: + + +{@example 'upgrade-module/ts/src/app/ajs-bootstrap/app.module.ts' region='bootstrap'} + +Now introduce Angular to the project. Inspired by instructions in +[the Setup](setup.html), you can selectively copy in material from the +<a href="https://github.com/angular/quickstart" target="_blank">QuickStart github repository</a>. + +Next, create an `app.module.ts` file and add the following `NgModule` class: + + +{@example 'upgrade-module/ts/src/app/ajs-a-hybrid-bootstrap/app.module.ts' region='ngmodule'} + +This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have. + +It also imports `UpgradeModule` from `@angular/upgrade/static`, and adds an override to prevent +Angular from bootstrapping itself in the form of the `ngDoBootstrap` empty class method. + +Now we bootstrap `AppModule` using `platformBrowserDynamic`'s `bootstrapModule` method. +Then we use dependency injection to get a hold of the `UpgradeModule` instance in `AppModule`, +and use it to bootstrap our AngularJS app. +The `upgrade.bootstrap` method takes the exact same arguments as [angular.bootstrap](https://docs.angularjs.org/api/ng/function/angular.bootstrap): + + +{@example 'upgrade-module/ts/src/app/ajs-a-hybrid-bootstrap/app.module.ts' region='bootstrap'} + +We also need to install the `@angular/upgrade` package via `npm install @angular/upgrade --save` +and add a mapping for the `@angular/upgrade/static` package: + + +{@example 'upgrade-module/ts/src/systemjs.config.1.js' region='upgrade-static-umd'} + +Congratulations! You're running a hybrid application! The +existing AngularJS code works as before _and_ you're ready to run Angular code. +### Using Angular Components from AngularJS Code +<figure> + <img src="/resources/images/devguide/upgrade/ajs-to-a.png" alt="Using an Angular component from AngularJS code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Once we're running a hybrid app, we can start the gradual process of upgrading +code. One of the more common patterns for doing that is to use an Angular component +in an AngularJS context. This could be a completely new component or one that was +previously AngularJS but has been rewritten for Angular. + +Say we have a simple Angular component that shows information about a hero: + + +{@example 'upgrade-module/ts/src/app/downgrade-static/hero-detail.component.ts'} + +If we want to use this component from AngularJS, we need to *downgrade* it +using the `downgradeComponent()` method. What we get when we do that is an AngularJS +*directive*, which we can then register into our AngularJS module: + + +{@example 'upgrade-module/ts/src/app/downgrade-static/app.module.ts' region='downgradecomponent'} + +Because `HeroDetailComponent` is an Angular component, we must also add it to the +`declarations` in the `AppModule`. + +And because this component is being used from the AngularJS module, and is an entry point into +our Angular application, we also need to add it to the `entryComponents` for our +Angular module. + + +{@example 'upgrade-module/ts/src/app/downgrade-static/app.module.ts' region='ngmodule'} + + +All Angular components, directives and pipes must be declared in an NgModule. +The net resulit is an AngularJS directive called `heroDetail`, that we can +use like any other directive in our AngularJS templates. + + +{@example 'upgrade-module/ts/src/index-downgrade-static.html' region='usecomponent'} + + + +~~~ {.alert.is-helpful} + +Note that this AngularJS is an element directive (`restrict: 'E'`) called `heroDetail`. +An AngularJS element directive is matched based on its _name_. +*The `selector` metadata of the downgraded Angular component is ignored.* + + + +~~~ + +Most components are not quite this simple, of course. Many of them +have *inputs and outputs* that connect them to the outside world. An +Angular hero detail component with inputs and outputs might look +like this: + + +{@example 'upgrade-module/ts/src/app/downgrade-io/hero-detail.component.ts'} + +These inputs and outputs can be supplied from the AngularJS template, and the +`downgradeComponent()` method takes care of bridging them over via the `inputs` +and `outputs` arrays: + + +{@example 'upgrade-module/ts/src/app/downgrade-io/app.module.ts' region='downgradecomponent'} + + + +{@example 'upgrade-module/ts/src/index-downgrade-io.html' region='usecomponent'} + +Note that even though we are in an AngularJS template, **we're using Angular +attribute syntax to bind the inputs and outputs**. This is a requirement for downgraded +components. The expressions themselves are still regular AngularJS expressions. + + +~~~ {.callout.is-important} + + +<header> + Use kebab-case for downgraded component attributes +</header> + +There's one notable exception to the rule of using Angular attribute syntax +for downgraded components. It has to do with input or output names that consist +of multiple words. In Angular we would bind these attributes using camelCase: +<code-example format=""> + [myHero]="hero" +</code-example> + +But when using them from AngularJS templates, we need to use kebab-case: +<code-example format=""> + [my-hero]="hero" + +</code-example> + + + +~~~ + +The `$event` variable can be used in outputs to gain access to the +object that was emitted. In this case it will be the `Hero` object, because +that is what was passed to `this.deleted.emit()`. + +Since this is an AngularJS template, we can still use other AngularJS +directives on the element, even though it has Angular binding attributes on it. +For example, we can easily make multiple copies of the component using `ng-repeat`: + + +{@example 'upgrade-module/ts/src/index-downgrade-io.html' region='userepeatedcomponent'} + +### Using AngularJS Component Directives from Angular Code +<figure> + <img src="/resources/images/devguide/upgrade/a-to-ajs.png" alt="Using an AngularJS component from Angular code" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +So, we can write an Angular component and then use it from AngularJS +code. This is very useful when we start our migration from lower-level +components and work our way up. But in some cases it is more convenient +to do things in the opposite order: To start with higher-level components +and work our way down. This too can be done using the `UpgradeModule`. +We can *upgrade* AngularJS component directives and then use them from +Angular. + +Not all kinds of AngularJS directives can be upgraded. The directive +really has to be a *component directive*, with the characteristics +[described in the preparation guide above](#using-component-directives). +Our safest bet for ensuring compatibility is using the +[component API](https://docs.angularjs.org/api/ng/type/angular.Module) +introduced in AngularJS 1.5. + +A simple example of an upgradable component is one that just has a template +and a controller: + + +{@example 'upgrade-module/ts/src/app/upgrade-static/hero-detail.component.ts' region='hero-detail'} + +We can *upgrade* this component to Angular using the `UpgradeComponent` class. +By creating a new Angular **directive** that extends `UpgradeComponent` and doing a `super` call +inside it's constructor, we have a fully upgrade AngularJS component to be used inside Angular. +All that is left is to add it to `AppModule`'s `declarations` array. + + +{@example 'upgrade-module/ts/src/app/upgrade-static/hero-detail.component.ts' region='hero-detail-upgrade'} + + + +{@example 'upgrade-module/ts/src/app/upgrade-static/app.module.ts' region='hero-detail-upgrade'} + + + +~~~ {.alert.is-helpful} + +Upgraded components are Angular **directives**, instead of **components**, because Angular +is unaware that AngularJS will create elements under it. As far as Angular knows, the upgraded +component is just a directive - a tag - and Angular doesn't have to concern itself with +it's children. + + +~~~ + +An upgraded component may also have inputs and outputs, as defined by +the scope/controller bindings of the original AngularJS component +directive. When we use the component from an Angular template, +we provide the inputs and outputs using **Angular template syntax**, +with the following rules: + +<table> + + <tr> + + <th> + + </th> + + + <th> + Binding definition + </th> + + + <th> + Template syntax + </th> + + + </tr> + + + <tr> + + <th> + Attribute binding + </th> + + + <td> + `myAttribute: '@myAttribute'` + </td> + + + <td> + `<my-component myAttribute="value">` + </td> + + + </tr> + + + <tr> + + <th> + Expression binding + </th> + + + <td> + `myOutput: '&myOutput'` + </td> + + + <td> + `<my-component (myOutput)="action()">` + </td> + + + </tr> + + + <tr> + + <th> + One-way binding + </th> + + + <td> + `myValue: '<myValue'` + </td> + + + <td> + `<my-component [myValue]="anExpression">` + </td> + + + </tr> + + + <tr> + + <th> + Two-way binding + </th> + + + <td> + `myValue: '=myValue'` + </td> + + + <td> + As a two-way binding: `<my-component [(myValue)]="anExpression">`. + Since most AngularJS two-way bindings actually only need a one-way binding + in practice, `<my-component [myValue]="anExpression">` is often enough. + + </td> + + + </tr> + + +</table> + +As an example, say we have a hero detail AngularJS component directive +with one input and one output: + + +{@example 'upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts' region='hero-detail-io'} + +We can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive, +and then provide the input and output using Angular template syntax: + + +{@example 'upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts' region='hero-detail-io-upgrade'} + + + +{@example 'upgrade-module/ts/src/app/upgrade-io/container.component.ts'} + +### Projecting AngularJS Content into Angular Components +<figure> + <img src="/resources/images/devguide/upgrade/ajs-to-a-with-projection.png" alt="Projecting AngularJS content into Angular" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +When we are using a downgraded Angular component from an AngularJS +template, the need may arise to *transclude* some content into it. This +is also possible. While there is no such thing as transclusion in Angular, +there is a very similar concept called *content projection*. The `UpgradeModule` +is able to make these two features interoperate. + +Angular components that support content projection make use of an `<ng-content>` +tag within them. Here's an example of such a component: + + +{@example 'upgrade-module/ts/src/app/ajs-to-a-projection/hero-detail.component.ts'} + +When using the component from AngularJS, we can supply contents for it. Just +like they would be transcluded in AngularJS, they get projected to the location +of the `<ng-content>` tag in Angular: + + +{@example 'upgrade-module/ts/src/index-ajs-to-a-projection.html' region='usecomponent'} + + + +~~~ {.alert.is-helpful} + +When AngularJS content gets projected inside an Angular component, it still +remains in "AngularJS land" and is managed by the AngularJS framework. + + +~~~ + +### Transcluding Angular Content into AngularJS Component Directives +<figure> + <img src="/resources/images/devguide/upgrade/a-to-ajs-with-transclusion.png" alt="Projecting Angular content into AngularJS" align="left" style="width:250px; margin-left:-40px;margin-right:10px"> </img> +</figure> + +Just like we can project AngularJS content into Angular components, +we can *transclude* Angular content into AngularJS components, whenever +we are using upgraded versions from them. + +When an AngularJS component directive supports transclusion, it may use +the `ng-transclude` directive in its template to mark the transclusion +point: + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-transclusion/hero-detail.component.ts'} + + + +~~~ {.alert.is-helpful} + +The directive also needs to have the `transclude: true` option enabled. +It is on by default for component directives defined with the +1.5 component API. + + +~~~ + +If we upgrade this component and use it from Angular, we can populate +the component tag with contents that will then get transcluded: + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-transclusion/container.component.ts'} + +### Making AngularJS Dependencies Injectable to Angular + +When running a hybrid app, we may bump into situations where we need to have +some AngularJS dependencies to be injected to Angular code. This may be +because we have some business logic still in AngularJS services, or because +we need some of AngularJS's built-in services like `$location` or `$timeout`. + +In these situations, it is possible to *upgrade* an AngularJS provider to +Angular. This makes it possible to then inject it somewhere in Angular +code. For example, we might have a service called `HeroesService` in AngularJS: + + +{@example 'upgrade-module/ts/src/app/ajs-to-a-providers/heroes.service.ts'} + +We can upgrade the service using a Angular [Factory provider](./dependency-injection.html#factory-providers) +that requests the service from the AngularJS `$injector`. + +We recommend declaring the Factory Provider in a separate `ajs-upgraded-providers.ts` file +so that they are all together, making it easier to reference them, create new ones and +delete them once the upgrade is over. + +It's also recommended to export the `heroesServiceFactory` function so that Ahead-of-Time +compilation can pick it up. + + +{@example 'upgrade-module/ts/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts'} + + + +{@example 'upgrade-module/ts/src/app/ajs-to-a-providers/app.module.ts' region='register'} + +We can then inject it in Angular using it's class as a type annotation: + + +{@example 'upgrade-module/ts/src/app/ajs-to-a-providers/hero-detail.component.ts'} + + + +~~~ {.alert.is-helpful} + +In this example we upgraded a service class, which has the added benefit that +we can use a TypeScript type annotation when we inject it. While it doesn't +affect how the dependency is handled, it enables the benefits of static type +checking. This is not required though, and any AngularJS service, factory, or +provider can be upgraded. + + +~~~ + +### Making Angular Dependencies Injectable to AngularJS + +In addition to upgrading AngularJS dependencies, we can also *downgrade* +Angular dependencies, so that we can use them from AngularJS. This can be +useful when we start migrating services to Angular or creating new services +in Angular while we still have components written in AngularJS. + +For example, we might have an Angular service called `Heroes`: + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-providers/heroes.ts'} + +Again, as with Angular components, register the provider with the `NgModule` by adding it to the module's `providers` list. + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-providers/app.module.ts' region='ngmodule'} + +Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()`. +and plug the factory into an AngularJS module. +The name of the AngularJS dependency is up to you: + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-providers/app.module.ts' region='register'} + +After this, the service is injectable anywhere in our AngularJS code: + + +{@example 'upgrade-module/ts/src/app/a-to-ajs-providers/hero-detail.component.ts'} + +## Using Ahead-of-time compilation with hybrid apps + +We can take advantage of Ahead-of-time (AoT) compilation on hybrid apps just like on any other +Angular application. +The setup for an hybrid app is mostly the same as described in +[the Ahead-of-time Compilation chapter](../cookbook/aot-compiler.html) +save for differences in `index.html` and `main-aot.ts` + +Our `index.html` will likely have script tags loading AngularJS files, so the `index.html` we +use for AoT must also load those files. +An easy way to copy them is by adding each to the `copy-dist-files.js` file. + +We also need to use `UpgradeModule` to bootstrap a hybrid app after bootstrapping the +Module Factory: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/main-aot.ts'} + +And that's all we need to get the full benefit of AoT for Angular apps! + + +~~~ {.alert.is-helpful} + +The AoT metadata collector will not detect lifecycle hook methods on a parent class' prototype, +so in order for upgraded components to work we needs to implement the lifecycle hooks +on the upgraded component class and forward them to the `UpgradeComponent` parent. + + +~~~ + +## Dividing routes between Angular and AngularJS + +Another important part of upgrading is upgrading routes. +We could upgrade our whole app while still using the AngularJS router and then +migrate all the routes in one fell swoop. +But it would be much better to migrate routes one by one as they become upgraded. + +The first step to have a dual router setup is to add an Angular root component containing +one outlet for each router. +AngularJS will use `ng-view`, and Angular will use `router-outlet`. +When one is using it's router, the other outlet will be empty. + + +{@example 'upgrade-module/ts/src/app/divide-routes/app.component.ts'} + +We want to use this component in the body of our `index.html` instead of an AngularJS component: + + +{@example 'upgrade-module/ts/src/index-divide-routes.html' region='body'} + +Next we declare both AngularJS and Angular routes as normal: + + +{@example 'upgrade-module/ts/src/app/divide-routes/app.module.ts' region='ajs-route'} + + + +{@example 'upgrade-module/ts/src/app/divide-routes/hero.module.ts' region='a-route'} + +In our `app.module.ts` we need to add `AppComponent` to the declarations and boostrap array. + +Next we configure the router itself. +We want to use [hash navigation](./router.html#-hashlocationstrategy-) in Angular +because that's what we're also using in AngularJS. + +Lastly, and most importantly, we want to use a custom `UrlHandlingStrategy` that will tell +the Angular router which routes it should render - and only those. + + +{@example 'upgrade-module/ts/src/app/divide-routes/app.module.ts' region='router-config'} + +That's it! Now we're running both routers at the same time. + + +## PhoneCat Upgrade Tutorial + +In this section and we will look at a complete example of +preparing and upgrading an application using the `upgrade` module. The app +we're going to work on is [Angular PhoneCat](https://github.com/angular/angular-phonecat) +from [the original AngularJS tutorial](https://docs.angularjs.org/tutorial), +which is where many of us began our Angular adventures. Now we'll see how to +bring that application to the brave new world of Angular. + +During the process we'll learn how to apply the steps outlined in the +[preparation guide](#preparation) in practice: We'll align the application +with Angular and also take TypeScript into use. + +To follow along with the tutorial, clone the +[angular-phonecat](https://github.com/angular/angular-phonecat) repository +and apply the steps as we go. + +In terms of project structure, this is where our work begins: + +<aio-filetree> + + <aio-folder> + angular-phonecat + <aio-file> + bower.json + </aio-file> + + + <aio-file> + karma.conf.js + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + <aio-folder> + app + <aio-folder> + core + <aio-folder> + checkmark + <aio-file> + checkmark.filter.js + </aio-file> + + + <aio-file> + checkmark.filter.spec.js + </aio-file> + + + </aio-folder> + + + <aio-folder> + phone + <aio-file> + phone.module.js + </aio-file> + + + <aio-file> + phone.service.js + </aio-file> + + + <aio-file> + phone.service.spec.js + </aio-file> + + + </aio-folder> + + + <aio-file> + core.module.js + </aio-file> + + + </aio-folder> + + + <aio-folder> + phone-detail + <aio-file> + phone-detail.component.js + </aio-file> + + + <aio-file> + phone-detail.component.spec.js + </aio-file> + + + <aio-file> + phone-detail.module.js + </aio-file> + + + <aio-file> + phone-detail.template.html + </aio-file> + + + </aio-folder> + + + <aio-folder> + phone-list + <aio-file> + phone-list.component.js + </aio-file> + + + <aio-file> + phone-list.component.spec.js + </aio-file> + + + <aio-file> + phone-list.module.js + </aio-file> + + + <aio-file> + phone-list.template.html + </aio-file> + + + </aio-folder> + + + <aio-folder> + img + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-folder> + phones + <aio-file> + ... + </aio-file> + + + </aio-folder> + + + <aio-file> + app.animations.js + </aio-file> + + + <aio-file> + app.config.js + </aio-file> + + + <aio-file> + app.css + </aio-file> + + + <aio-file> + app.module.js + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + </aio-folder> + + + <aio-folder> + e2e-tests + <aio-file> + protractor-conf.js + </aio-file> + + + <aio-file> + scenarios.js + </aio-file> + + + </aio-folder> + + + </aio-folder> + + +</aio-filetree> + +This is actually a pretty good starting point. The code uses the AngularJS 1.5 +component API and the organization follows the +[AngularJS Style Guide](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md), +which is an important [preparation step](#following-the-angular-style-guide) before +a successful upgrade. + +* Each component, service, and filter is in its own source file, as per the + [Rule of 1](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#single-responsibility). +* The `core`, `phone-detail`, and `phone-list` modules are each in their + own subdirectory. Those subdirectories contain the JavaScript code as well as + the HTML templates that go with each particular feature. This is in line with the + [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y152) + and [Modularity](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modularity) + rules. +* Unit tests are located side-by-side with application code where they are easily + found, as described in the rules for + [Organizing Tests](https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y197). +### Switching to TypeScript + +Since we're going to be writing our Angular code in TypeScript, it makes sense to +bring in the TypeScript compiler even before we begin upgrading. + +We will also start to gradually phase out the Bower package manager in favor +of NPM. We'll install all new dependencies using NPM, and will eventually be +able to remove Bower from the project. + +Let's begin by installing TypeScript to the project. + +<code-example format=""> + npm i typescript --save-dev + +</code-example> + +Let's also add run scripts for the `tsc` TypeScript compiler to `package.json`: +We can now install type definitions for the existing libraries that +we're using but that don't come with prepackaged types: AngularJS and the +Jasmine unit test framework. + +<code-example format=""> + npm install @types/jasmine @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev + +</code-example> + +We should also configure the TypeScript compiler so that it can understand our +project. We'll add a `tsconfig.json` file to the project directory, just like we do +in the documentation [setup](setup.html). It instructs the TypeScript compiler how +to interpret our source files. +We are telling the TypeScript compiler to turn our TypeScript files to ES5 code +bundled into CommonJS modules. + +We can now launch the TypeScript compiler from the command line. It will watch +our `.ts` source files and compile them to JavaScript on the fly. Those compiled +`.js` files are then loaded into the browser by SystemJS. This is a process we'll +want to have continuously running in the background as we go along. + +<code-example format=""> + npm run tsc:w + +</code-example> + +The next thing we'll do is convert our JavaScript files to TypeScript. Since +TypeScript is a superset of ECMAScript 2015, which in turn is a superset +of ECMAScript 5, we can simply switch the file extensions from `.js` to `.ts` +and everything will work just like it did before. As the TypeScript compiler +runs, it emits the corresponding `.js` file for every `.ts` file and the +compiled JavaScript is what actually gets executed. If you start +the project HTTP server with `npm start`, you should see the fully functional +application in your browser. + +Now that we have TypeScript though, we can start benefiting from some of its +features. There's a lot of value the language can provide to AngularJS applications. + +For one thing, TypeScript is a superset of ES2015. Any app that has previously +been written in ES5 - like the PhoneCat example has - can with TypeScript +start incorporating all of the JavaScript features that are new to ES2015. +These include things like `let`s and `const`s, arrow functions, default function +parameters, and destructuring assignments. + +Another thing we can do is start adding *type safety* to our code. This has +actually partially already happened because of the AngularJS typings we installed. +TypeScript are checking that we are calling AngularJS APIs correctly when we do +things like register components to Angular modules. + +But we can also start adding *type annotations* for our own code to get even more +out of TypeScript's type system. For instance, we can annotate the checkmark +filter so that it explicitly expects booleans as arguments. This makes it clearer +what the filter is supposed to do. + + +{@example 'upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.ts'} + +In the `Phone` service we can explicitly annotate the `$resource` service dependency +as an `angular.resource.IResourceService` - a type defined by the AngularJS typings. + + +{@example 'upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts'} + +We can apply the same trick to the application's route configuration file in `app.config.ts`, +where we are using the location and route services. By annotating them accordingly TypeScript +can verify we're calling their APIs with the correct kinds of arguments. + + +{@example 'upgrade-phonecat-1-typescript/ts/app/app.config.ts'} + + +The [AngularJS 1.x type definitions](https://www.npmjs.com/package/@types/angular) +we installed are not officially maintained by the Angular team, +but are quite comprehensive. It is possible to make an AngularJS 1.x application +fully type-annotated with the help of these definitions. + +If this is something we wanted to do, it would be a good idea to enable +the `noImplicitAny` configuration option in `tsconfig.json`. This would +cause the TypeScript compiler to display a warning when there's any code that +does not yet have type annotations. We could use it as a guide to inform +us about how close we are to having a fully annotated project. +Another TypeScript feature we can make use of is *classes*. In particular, we +can turn our component controllers into classes. That way they'll be a step +closer to becoming Angular component classes, which will make our life +easier once we do the upgrade. + +AngularJS expects controllers to be constructor functions. That's exactly what +ES2015/TypeScript classes are under the hood, so that means we can just plug in a +class as a component controller and AngularJS will happily use it. + +Here's what our new class for the phone list component controller looks like: + + +{@example 'upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.ts'} + +What was previously done in the controller function is now done in the class +constructor function. The dependency injection annotations are attached +to the class using a static property `$inject`. At runtime this becomes the +`PhoneListController.$inject` property. + +The class additionally declares three members: The array of phones, the name of +the current sort key, and the search query. These are all things we have already +been attaching to the controller but that weren't explicitly declared anywhere. +The last one of these isn't actually used in the TypeScript code since it's only +referred to in the template, but for the sake of clarity we want to define all the +members our controller will have. + +In the Phone detail controller we'll have two members: One for the phone +that the user is looking at and another for the URL of the currently displayed image: + + +{@example 'upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts'} + +This makes our controller code look a lot more like Angular already. We're +all set to actually introduce Angular into the project. + +If we had any AngularJS services in the project, those would also be +a good candidate for converting to classes, since like controllers, +they're also constructor functions. But we only have the `Phone` factory +in this project, and that's a bit special since it's an `ngResource` +factory. So we won't be doing anything to it in the preparation stage. +We'll instead turn it directly into an Angular service. + +### Installing Angular + +Having completed our preparation work, let's get going with the Angular +upgrade of PhoneCat. We'll do this incrementally with the help of the +[upgrade module](#upgrading-with-the-upgrade-module) that comes with Angular. +By the time we're done, we'll be able to remove AngularJS from the project +completely, but the key is to do this piece by piece without breaking the application. + + +~~~ {.alert.is-important} + +The project also contains some animations, which we are not yet upgrading in this version of the guide. This will change in a later release. + +~~~ + +Let's install Angular into the project, along with the SystemJS module loader. +Take a look at the results of the [Setup](setup.html) instructions +and get the following configurations from there: + +* Add Angular and the other new dependencies to `package.json` +* The SystemJS configuration file `systemjs.config.js` to the project root directory. + +Once these are done, run: + +<code-example format=""> + npm install + +</code-example> + +We can soon load Angular dependencies into the application via `index.html`, +but first we need to do some directory path adjustments. This is because we're going +to need to load files from `node_modules` and the project root, whereas so far +in this project everything has been loaded from the `/app` directory. + +Move the `app/index.html` file to the project root directory. Then change the +development server root path in `package.json` to also point to the project root +instead of `app`: +Now we're able to serve everything from the project root to the web browser. But we do *not* +want to have to change all the image and data paths used in the application code to match +our development setup. For that reason, we'll add a `<base>` tag to `index.html`, which will +cause relative URLs to be resolved back to the `/app` directory: + + +{@example 'upgrade-phonecat-2-hybrid/ts/index.html' region='base'} + +Now we can load Angular via SystemJS. We'll add the Angular polyfills and the +SystemJS config to the end of the `<head>` section, and then we'll use `System.import` +to load the actual application: + + +{@example 'upgrade-phonecat-2-hybrid/ts/index.html' region='angular'} + +We also need to make a couple of adjustments +to the `systemjs.config.js` file installed during [setup](setup.html). + +We want to point the browser to the project root when loading things through SystemJS, +instead of using the `<base>` URL. + +We also need to install the `upgrade` package via `npm install @angular/upgrade --save` +and add a mapping for the `@angular/upgrade/static` package. + + +{@example 'upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js' region='paths'} + +### Creating the _AppModule_ + +Now create the root `NgModule` class called `AppModule`. +There is already a file named `app.module.ts` that holds the AngularJS module. +Rename it to `app.module.ajs.ts` and update the corresponding script name in the `index.html` as well. +The file contents remain: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ajs.ts'} + +Now create a new `app.module.ts` with the minimum `NgModule` class: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='bare'} + +### Bootstrapping a hybrid PhoneCat + +What we'll do next is bootstrap the application as a *hybrid application* +that supports both AngularJS and Angular components. Once we've done that +we can start converting the individual pieces to Angular. + +To [bootstrap a hybrid application](#bootstrapping-hybrid-applications), +we first need to import `UpgradeModule` in our `AppModule`, and override it's bootstrap method: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='upgrademodule'} + +Our application is currently bootstrapped using the AngularJS `ng-app` directive +attached to the `<html>` element of the host page. This will no longer work with +Angular. We should switch to a JavaScript-driven bootstrap instead. + +So, remove the `ng-app` attribute from `index.html`, and instead bootstrap via `src/main.ts`. +This file has been configured as the application entrypoint in `systemjs.config.js`, +so it is already being loaded by the browser. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/main.ts' region='bootstrap'} + +The arguments used here are the root element of the application (which is +the same element we had `ng-app` on earlier), and the AngularJS 1.x modules +that we want to load. Since we're bootstrapping the app through +an `UpgradeModule`, we're actually now running the app as a **hybrid app**. + +This means we are now running both AngularJS and Angular at the same time. That's pretty +exciting! We're not running any actual Angular components yet though, +so let's do that next. + +#### Why declare _angular_ as _angular.IAngularStatic_? + +`@types/angular` is declared as a UMD module, and due to the way +<a href="https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#support-for-umd-module-definitions" target="_blank">UMD typings</a> +work, once you have an ES6 `import` statement in a file all UMD typed modules must also be +imported via `import` statements instead of being globally available. + +AngularJS is currently loaded by a script tag in `index.html`, which means that the whole app +has access to it as a global and uses the same instance of the `angular` variable. +If we used `import * as angular from 'angular'` instead we would also need to overhaul how we +load every file in our AngularJS app to use ES6 modules in order to ensure AngularJS was being +loaded correctly. + +This is a considerable effort and it often isn't worth it, especially since we are in the +process of moving our our to Angular already. +Instead we declare `angular` as `angular.IAngularStatic` to indicate it is a global variable +and still have full typing support. +### Upgrading the Phone service + +The first piece we'll port over to Angular is the `Phone` service, which +resides in `app/core/phone/phone.service.ts` and makes it possible for components +to load phone information from the server. Right now it's implemented with +ngResource and we're using it for two things: + +* For loading the list of all phones into the phone list component +* For loading the details of a single phone into the phone detail component. + +We can replace this implementation with an Angular service class, while +keeping our controllers in AngularJS land. + +In the new version, we import the Angular HTTP module and call its `Http` service instead of `ngResource`. + +Re-open the `app.module.ts` file, import and add `HttpModule` to the `imports` array of the `AppModule`: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='httpmodule'} + +Now we're ready to upgrade the Phone service itself. We replace the ngResource-based +service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts' region='classdef'} + +The `@Injectable` decorator will attach some dependency injection metadata +to the class, letting Angular know about its dependencies. As described +by our [Dependency Injection Guide](./dependency-injection.html), +this is a marker decorator we need to use for classes that have no other +Angular decorators but still need to have their dependencies injected. + +In its constructor the class expects to get the `Http` service. It will +be injected to it and it is stored as a private field. The service is then +used in the two instance methods, one of which loads the list of all phones, +and the other the details of a particular phone: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts' region='fullclass'} + +The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is +a type we don't have yet, so let's add a simple interface for it: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts' region='phonedata-interface'} + +`@angular/upgrade/static` has a `downgradeInjectable` method for the purpose of making +Angular services available to AngularJS code. Use it to plug in the `Phone` service: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts' region='downgrade-injectable'} + +Here's the full, final code for the service: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts'} + +Notice that we're importing the `map` operator of the RxJS `Observable` separately. +We need to do this for all RxJS operators that we want to use, since Angular +does not load all of them by default. + +The new `Phone` service has the same features as the original, `ngResource`-based service. +Because it's an Angular service, we register it with the `NgModule` providers: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='phone'} + +Now that we are loading `phone.service.ts` through an import that is resolved +by SystemJS, we should **remove the <script> tag** for the service from `index.html`. +This is something we'll do to all our components as we upgrade them. Simultaneously +with the AngularJS to Angular upgrade we're also migrating our code from scripts to modules. + +At this point we can switch our two components to use the new service +instead of the old one. We `$inject` it as the downgraded `phone` factory, +but it's really an instance of the `Phone` class and we can annotate its type +accordingly: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ajs.ts'} + + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ajs.ts'} + +What we have here are two AngularJS components using an Angular service! +The components don't need to be aware of this, though the fact that the +service returns Observables and not Promises is a bit of a giveaway. +In any case, what we've achieved is a migration of a service to Angular +without having to yet migrate the components that use it. + + +~~~ {.alert.is-helpful} + +We could also use the `toPromise` method of `Observable` to turn those +Observables into Promises in the service. This can in many cases further +reduce the amount of changes needed in the component controllers. + + +~~~ + +### Upgrading Components + +Next, let's upgrade our AngularJS components to Angular components. We'll +do it one at a time, while still keeping the application in hybrid mode. +As we make these conversions, we'll also be defining our first Angular *pipes*. + +Let's look at the phone list component first. Right now it contains a TypeScript +controller class and a component definition object. We can morph this into +an Angular component by just renaming the controller class and turning the +AngularJS component definition object into an Angular `@Component` decorator. +We can then also remove the static `$inject` property from the class: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts' region='initialclass'} + +The `selector` attribute is a CSS selector that defines where on the page the component +should go. In AngularJS we do matching based on component names, but in Angular we +have these explicit selectors. This one will match elements with the name `phone-list`, +just like the AngularJS version did. + +We now also need to convert the template of this component into Angular syntax. +The search controls replace the AngularJS `$ctrl` expressions +with Angular's two-way `[(ngModel)]` binding syntax: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html' region='controls'} + +Replace the list's `ng-repeat` with an `*ngFor` as +[described in the Template Syntax page](../guide/template-syntax.html#directives). +Replace the image tag's `ng-src` with a binding to the native `src` property. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html' region='list'} + +#### No Angular _filter_ or _orderBy_ filters +The built-in AngularJS `filter` and `orderBy` filters do not exist in Angular, +so we need to do the filtering and sorting ourselves. + +We replaced the `filter` and `orderBy` filters with bindings to the `getPhones()` controller method, +which implements the filtering and ordering logic inside the component itself. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts' region='getphones'} + +Now we need to downgrade our Angular component so we can use it in AngularJS. +Instead of registering a component, we register a `phoneList` *directive*, +a downgraded version of the Angular component. + +The `as angular.IDirectiveFactory` cast tells the TypeScript compiler +that the return value of the `downgradeComponent` method is a directive factory. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts' region='downgrade-component'} + +The new `PhoneListComponent` uses the Angular `ngModel` directive, located in the `FormsModule`. +Add the `FormsModule` to `NgModule` imports, declare the new `PhoneListComponent` and +finally add it to `entryComponents` since we downgraded it: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='phonelist'} + +Remove the <script> tag for the phone list component from `index.html`. + +Now set the remaining `phone-detail.component.ts` as follows: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts'} + +This is similar to the phone list component. +The new wrinkle is the `RouteParams` type annotation that identifies the `routeParams` dependency. + +The AngularJS injector has an AngularJS router dependency called `$routeParams`. +which was injected into `PhoneDetails` when it was still an AngularJS controller. +We intend to inject it into the new `PhoneDetailsComponent`. + +Unfortunately, AngularJS dependencies are not automatically available to Angular components. +We must use a [Factory provider](#making-angularjs-dependencies-injectable-to-angular) +to make `$routeParams` an Angular provider. +Do that in a new file called `ajs-upgraded-providers.ts` and import it in `app.module.ts`: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/ajs-upgraded-providers.ts'} + + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='routeparams'} + +Convert the phone detail component template into Angular syntax as follows: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html'} + +There are several notable changes here: + +* We've removed the `$ctrl.` prefix from all expressions. +* Just like we did in the phone list, we've replaced `ng-src` with property + bindings for the standard `src` property. +* We're using the property binding syntax around `ng-class`. Though Angular + does have [a very similar `ngClass`](../guide/template-syntax.html#directives) + as AngularJS does, its value is not magically evaluated as an expression. + In Angular we always specify in the template when an attribute's value is + a property expression, as opposed to a literal string. +* We've replaced `ng-repeat`s with `*ngFor`s. +* We've replaced `ng-click` with an event binding for the standard `click`. +* We've wrapped the whole template in an `ngIf` that causes it only to be + rendered when there is a phone present. We need this because when the component + first loads, we don't have `phone` yet and the expressions will refer to a + non-existing value. Unlike in AngularJS, Angular expressions do not fail silently + when we try to refer to properties on undefined objects. We need to be explicit + about cases where this is expected. + +Add `PhoneDetailComponent` component to the `NgModule` _declarations_ and _entryComponents_: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='phonedetail'} + +We should now also remove the phone detail component <script> tag from `index.html`. + +#### Add the _CheckmarkPipe_ + +The AngularJS directive had a `checkmark` _filter_. +Let's turn that into an Angular **pipe**. + +There is no upgrade method to convert filters into pipes. +You won't miss it. +It's easy to turn the filter function into an equivalent Pipe class. +The implementation is the same as before, repackaged in the `transform` method. +Rename the file to `checkmark.pipe.ts` to conform with Angular conventions: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts'} + +Now import and declare the newly created pipe and +remove the filter <script> tag from `index.html`: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/app.module.ts' region='checkmarkpipe'} + +## AoT compile the hybrid app + +To use AoT with our hybrid app we have to first set it up like any other Angular application, +as shown in [the Ahead-of-time Compilation chapter](../cookbook/aot-compiler.html). + +Then we have to change `main-aot.ts` bootstrap also bootstrap the AngularJS app +via `UpgradeModule`: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/main-aot.ts'} + +We need to load all the AngularJS files we already use in `index.html` in `aot/index.html` +as well: + + +{@example 'upgrade-phonecat-2-hybrid/ts/aot/index.html'} + +These files need to be copied together with the polyfills. Files our application +needs at runtime, like the `.json` phone lists and images, also need to be copied. + +Install `fs-extra` via `npm install fs-extra --save-dev` for better file copying, and change +`copy-dist-files.js` to the following: + + +{@example 'upgrade-phonecat-2-hybrid/ts/copy-dist-files.js'} + +And that's all you need to use AoT while upgrading your app! +### Adding The Angular Router And Bootstrap + +At this point we've replaced all AngularJS application components with +their Angular counterparts, even though we're still serving them from the AngularJS router. + +Most AngularJS apps have more than a couple of routes though, and it's very helpful to migrate +one route at a time. + +Let's start by migrating the initial `/` and `/phones` routes to Angular, +while keeping `/phones/:phoneId` in the AngularJS router. + +#### Add the Angular router + +Angular has an [all-new router](router.html). + +Like all routers, it needs a place in the UI to display routed views. +For Angular that's the `<router-outlet>` and it belongs in a *root component* +at the top of the applications component tree. + +We don't yet have such a root component, because the app is still managed as an AngularJS app. +Create a new `app.component.ts` file with the following `AppComponent` class: + + +{@example 'upgrade-phonecat-3-router/ts/app/app.component.ts'} + +It has a simple template that only includes the `<router-outlet>` for Angular routes +and `ng-view` for AngularJS routes. +This component just renders the contents of the active route and nothing else. + +The selector tells Angular to plug this root component into the `<phonecat-app>` +element on the host web page when the application launches. + +Add this `<phonecat-app>` element to the `index.html`. +It replaces the old AngularJS `ng-view` directive: + + +{@example 'upgrade-phonecat-3-router/ts/index.html' region='appcomponent'} + +#### Create the _Routing Module_ +A router needs configuration whether it's the AngularJS or Angular or any other router. + +The details of Angular router configuration are best left to the [Routing documentation](router.html) +which recommends that you create a `NgModule` dedicated to router configuration +(called a _Routing Module_). + + +{@example 'upgrade-phonecat-3-router/ts/app/app-routing.module.ts'} + +This module defines a `routes` object with one route to the phone list component +and a default route for the empty path. +It passes the `routes` to the `RouterModule.forRoot` method which does the rest. + +A couple of extra providers enable routing with "hash" URLs such as `#!/phones` +instead of the default "push state" strategy. + +There's a twist to our Routing Module though: we're also adding a custom `UrlHandlingStrategy` +that tells the Angular router to only process the `/` and `/phones` routes. + +Now update the `AppModule` to import this `AppRoutingModule` and also the +declare the root `AppComponent` as the bootstrap component. +That tells Angular that it should bootstrap the app with the _root_ `AppComponent` and +insert it's view into the host web page. + +We can also remove the `ngDoBootstrap()` override from `app.module.ts` since we are now +bootstrapping from Angular. + +And since `PhoneListComponent` isn't being rendered from a `<phone-list>` tag anymore, +but rather routed to, we can do away with it's Angular selector as well. + + +{@example 'upgrade-phonecat-3-router/ts/app/app.module.ts'} + +Now we need to tell the AngularJS router to only process the `/phones/:phoneId` route: + + +{@example 'upgrade-phonecat-3-router/ts/app/app.config.ts' region='ajs-routes'} + +#### Generate links for each phone + +We no longer have to hardcode the links to phone details in the phone list. +We can generate data bindings for each phone's `id` to the `routerLink` directive +and let that directive construct the appropriate URL to the `PhoneDetailComponent`: + + +{@example 'upgrade-phonecat-3-router/ts/app/phone-list/phone-list.template.html' region='list'} + + +See the [Routing](router.html) page for details. +We are now running both routers at the same time! +Angular is handling the initial `/` url, redirecting to `/phones`. +Meanwhile when we click a link to the phone detail, AngularJS takes over. + +This way we can incrementally upgrade our app, reducing the risk of a massive one step router +swap. + +The next step is to migrate the `/phones/:phoneId` route. +The Angular router passes route parameters differently. +Correct the `PhoneDetail` component constructor to expect an injected `ActivatedRoute` object. +Extract the `phoneId` from the `ActivatedRoute.snapshot.params` and fetch the phone data as before: + + +{@example 'upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.ts'} + +Since this was the last route we want to migrate over, we can also now delete the last +route config from `app/app.config.ts`, and add it to the Angular router configuration. + +We don't need our `UrlHandlingStrategy` anymore either, since now Angular is processing all +routes. + + +{@example 'upgrade-phonecat-4-final/ts/app/app-routing.module.ts'} + +You are now running a pure Angular application! + +### Say Goodbye to AngularJS + +It is time to take off the training wheels and let our application begin +its new life as a pure, shiny Angular app. The remaining tasks all have to +do with removing code - which of course is every programmer's favorite task! + +The application is still bootstrapped as a hybrid app. +There's no need for that anymore. + +Switch the bootstrap method of the application from the `UpgradeAdapter` +to the Angular way. + + +{@example 'upgrade-phonecat-4-final/ts/app/main.ts'} + +If you haven't already, remove all references to the `UpgradeModule` from `app.module.ts`, +as well as any [Factory provider](#making-angularjs-dependencies-injectable-to-angular) +for AngularJS services, and the `app/ajs-upgraded-providers.ts` file. + +Also remove any `downgradeInjectable()` or `downgradeComponent()` you find, +together with the associated AngularJS factory or directive declarations. +Since we have no downgraded components anymore, we also don't need to have them listed +in `entryComponents` either. + + +{@example 'upgrade-phonecat-4-final/ts/app/app.module.ts'} + +You may also completely remove the following files. They are AngularJS +module configuration files and not needed in Angular: + +* `app/app.module.ajs.ts` +* `app/app.config.ts` +* `app/core/core.module.ts` +* `app/core/phone/phone.module.ts` +* `app/phone-detail/phone-detail.module.ts` +* `app/phone-list/phone-list.module.ts` + +The external typings for AngularJS may be uninstalled as well. The only ones +we still need are for Jasmine and Angular polyfills. +The `@angular/upgrade` package and it's mapping in `systemjs.config.js` can also go. + +<code-example format=""> + npm uninstall @angular/upgrade --save + npm uninstall @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev + +</code-example> + +Finally, from `index.html`, remove all references to +AngularJS scripts, the Angular upgrade module, and jQuery. When we're done, +this is what it should look like: + + +{@example 'upgrade-phonecat-4-final/ts/index.html' region='full'} + +That is the last we'll see of AngularJS! It has served us well but now +it's time to say goodbye. + + + +## Appendix: Upgrading PhoneCat Tests + +Tests can not only be retained through an upgrade process, but they can also be +used as a valuable safety measure when ensuring that the application does not +break during the upgrade. E2E tests are especially useful for this purpose. + +### E2E Tests + +The PhoneCat project has both E2E Protractor tests and some Karma unit tests in it. +Of these two, E2E tests can be dealt with much more easily: By definition, +E2E tests access our application from the *outside* by interacting with +the various UI elements the app puts on the screen. E2E tests aren't really that +concerned with the internal structure of the application components. That +also means that although we modify our project quite a bit during the upgrade, the E2E +test suite should keep passing with just minor modifications. This is because +we don't change how the application behaves from the user's point of view. + +During TypeScript conversion, there is nothing we have to do to keep E2E tests +working. It is only when we change our bootstrap to that of a Hybrid app that we need to +make some changes. + +The following change is needed in `protractor-conf.js` to sync with hybrid apps: +<code-example format=""> + ng12Hybrid: true + +</code-example> + +The next set of changes is when we start to upgrade components and their template to Angular. +This is because the E2E tests have matchers that are specific to AngularJS. +For PhoneCat we need to make the following changes in order to make things work with Angular: + +<table> + + <tr> + + <th> + Previous code + </th> + + + <th> + New code + </th> + + + <th> + Notes + </th> + + + </tr> + + + <tr> + + <td> + `by.repeater('phone in $ctrl.phones').column('phone.name')` + </td> + + + <td> + `by.css('.phones .name')` + </td> + + + <td> + The repeater matcher relies on AngularJS `ng-repeat` + </td> + + + </tr> + + + <tr> + + <td> + `by.repeater('phone in $ctrl.phones')` + </td> + + + <td> + `by.css('.phones li')` + </td> + + + <td> + The repeater matcher relies on AngularJS `ng-repeat` + </td> + + + </tr> + + + <tr> + + <td> + `by.model('$ctrl.query')` + </td> + + + <td> + `by.css('input')` + </td> + + + <td> + The model matcher relies on AngularJS `ng-model` + </td> + + + </tr> + + + <tr> + + <td> + `by.model('$ctrl.orderProp')` + </td> + + + <td> + `by.css('select')` + </td> + + + <td> + The model matcher relies on AngularJS `ng-model` + </td> + + + </tr> + + + <tr> + + <td> + `by.binding('$ctrl.phone.name')` + </td> + + + <td> + `by.css('h1')` + </td> + + + <td> + The binding matcher relies on AngularJS data binding + + + </td> + + + </tr> + + +</table> + +When the bootstrap method is switched from that of `UpgradeModule` to +pure Angular, AngularJS ceases to exist on the page completely. +At this point we need to tell Protractor that it should not be looking for +an AngularJS app anymore, but instead it should find *Angular apps* from +the page. + +Replace the `ng12Hybrid` previously added with the following in `protractor-conf.js`: + +<code-example format=""> + useAllAngular2AppRoots: true, + +</code-example> + +Also, there are a couple of Protractor API calls in the PhoneCat test code that +are using the AngularJS `$location` service under the hood. As that +service is no longer there after the upgrade, we need to replace those calls with ones +that use WebDriver's generic URL APIs instead. The first of these is +the redirection spec: + + +{@example 'upgrade-phonecat-4-final/e2e-spec.ts' region='redirect'} + +And the second is the phone links spec: + + +{@example 'upgrade-phonecat-4-final/e2e-spec.ts' region='links'} + +### Unit Tests + +For unit tests, on the other hand, more conversion work is needed. Effectively +they need to be *upgraded* along with the production code. + +During TypeScript conversion no changes are strictly necessary. But it may be +a good idea to convert the unit test code into TypeScript as well, as the same +benefits we from TypeScript in production code also applies to tests. + +For instance, in the phone detail component spec we can use not only ES2015 +features like arrow functions and block-scoped variables, but also type +definitions for some of the AngularJS services we're consuming: + + +{@example 'upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts'} + +Once we start the upgrade process and bring in SystemJS, configuration changes +are needed for Karma. We need to let SystemJS load all the new Angular code, +which can be done with the following kind of shim file: + + +{@example 'upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js'} + +The shim first loads the SystemJS configuration, then Angular's test support libraries, +and then the application's spec files themselves. + +Karma configuration should then be changed so that it uses the application root dir +as the base directory, instead of `app`. + + +{@example 'upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js' region='basepath'} + +Once this is done, we can load SystemJS and other dependencies, and also switch the configuration +for loading application files so that they are *not* included to the page by Karma. We'll let +the shim and SystemJS load them. + + +{@example 'upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js' region='files'} + +Since the HTML templates of Angular components will be loaded as well, we need to help +Karma out a bit so that it can route them to the right paths: + + +{@example 'upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js' region='html'} + +The unit test files themselves also need to be switched to Angular when their production +counterparts are switched. The specs for the checkmark pipe are probably the most straightforward, +as the pipe has no dependencies: + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts'} + +The unit test for the phone service is a bit more involved. We need to switch from the mocked-out +AngularJS `$httpBackend` to a mocked-out Angular Http backend. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts'} + +For the component specs we can mock out the `Phone` service itself, and have it provide +canned phone data. We use Angular's component unit testing APIs for both components. + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts'} + + + +{@example 'upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts'} + +Finally, we need to revisit both of the component tests when we switch to the Angular +router. For the details component we need to provide a mock of Angular `ActivatedRoute` object +instead of using the AngularJS `$routeParams`. + + +{@example 'upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.spec.ts' region='activatedroute'} + +And for the phone list component we need to set up a few things for the router itself so that +the route link directive will work. + + +{@example 'upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.spec.ts' region='routestuff'} + diff --git a/aio/content/guide/user-input.md b/aio/content/guide/user-input.md new file mode 100644 index 0000000000..c6db0de119 --- /dev/null +++ b/aio/content/guide/user-input.md @@ -0,0 +1,256 @@ +@title +User Input + +@intro +User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models. + +@description +User actions such as clicking a link, pushing a button, and entering +text raise DOM events. +This page explains how to bind those events to component event handlers using the Angular +event binding syntax. + +Run the <live-example></live-example>. +## Binding to user input events + +You can use [Angular event bindings](./template-syntax.html#event-binding) +to respond to any [DOM event](https://developer.mozilla.org/en-US/docs/Web/Events). +Many DOM events are triggered by user input. Binding to these events provides a way to +get input from the user. + +To bind to a DOM event, surround the DOM event name in parentheses and assign a quoted +[template statement](./template-syntax.html#template-statements) to it. + +The following example shows an event binding that implements a click handler: + +{@example 'user-input/ts/src/app/click-me.component.ts' region='click-me-button'} + +<a id="click"></a>The `(click)` to the left of the equals sign identifies the button's click event as the **target of the binding**. +The text in quotes to the right of the equals sign +is the **template statement**, which responds +to the click event by calling the component's `onClickMe` method. + +When writing a binding, be aware of a template statement's **execution context**. +The identifiers in a template statement belong to a specific context object, +usually the Angular component controlling the template. +The example above shows a single line of HTML, but that HTML belongs to a larger component: + + +{@example 'user-input/ts/src/app/click-me.component.ts' region='click-me-component'} + +When the user clicks the button, Angular calls the `onClickMe` method from `ClickMeComponent`. + +## Get user input from the $event object +DOM events carry a payload of information that may be useful to the component. +This section shows how to bind to the `keyup` event of an input box to get the user's input after each keystroke. + +The following code listens to the `keyup` event and passes the entire event payload (`$event`) to the component event handler. + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-1-template'} + +When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding +DOM event object in the `$event` variable which this code passes as a parameter to the component's `onKey()` method. + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-1-class-no-type'} + +The properties of an `$event` object vary depending on the type of DOM event. For example, +a mouse event includes different information than a input box editing event. + +All [standard DOM event objects](https://developer.mozilla.org/en-US/docs/Web/API/Event) +have a `target` property, a reference to the element that raised the event. +In this case, `target` refers to the [`<input>` element](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) and +`event.target.value` returns the current contents of that element. + +After each call, the `onKey()` method appends the contents of the input box value to the list +in the component's `values` property, followed by a separator character (|). +The [interpolation](./template-syntax.html#interpolation) +displays the accumulating input box changes from the `values` property. + +Suppose the user enters the letters "abc", and then backspaces to remove them one by one. +Here's what the UI displays: +<code-example> + a | ab | abc | ab | a | | +</code-example> + + +<figure class='image-display'> + <img src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1"> </img> +</figure> + + +Alternatively, you could accumulate the individual keys themselves by substituting `event.key` +for `event.target.value` in which case the same user input would produce: +<code-example> + a | b | c | backspace | backspace | backspace | + +</code-example> + + + +{@a keyup1} +### Type the _$event_ + +The example above casts the `$event` as an `any` type. +That simplifies the code at a cost. +There is no type information +that could reveal properties of the event object and prevent silly mistakes. + +The following example rewrites the method with types: + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-1-class'} + +The `$event` is now a specific `KeyboardEvent`. +Not all elements have a `value` property so it casts `target` to an input element. +The `OnKey` method more clearly expresses what it expects from the template and how it interprets the event. + +### Passing _$event_ is a dubious practice +Typing the event object reveals a significant objection to passing the entire DOM event into the method: +the component has too much awareness of the template details. +It can't extract information without knowing more than it should about the HTML implementation. +That breaks the separation of concerns between the template (_what the user sees_) +and the component (_how the application processes user data_). + +The next section shows how to use template reference variables to address this problem. + +## Get user input from a template reference variable +There's another way to get the user data: use Angular +[**template reference variables**](./template-syntax.html#ref-vars). +These variables provide direct access to an element from within the template. +To declare a template reference variable, precede an identifier with a hash (or pound) character (#). + +The following example uses a template reference variable +to implement a keystroke loopback in a simple template. + +{@example 'user-input/ts/src/app/loop-back.component.ts' region='loop-back-component'} + +The template reference variable named `box`, declared on the `<input>` element, +refers to the `<input>` element itself. +The code uses the `box` variable to get the input element's `value` and display it +with interpolation between `<p>` tags. + +The template is completely self contained. It doesn't bind to the component, +and the component does nothing. + +Type something in the input box, and watch the display update with each keystroke. + +<figure class='image-display'> + <img src='/resources/images/devguide/user-input/keyup-loop-back-anim.gif' alt="loop back"> </img> +</figure> + + +**This won't work at all unless you bind to an event**. + +Angular updates the bindings (and therefore the screen) +only if the app does something in response to asynchronous events, such as keystrokes. +This example code binds the `keyup` event +to the number 0, the shortest template statement possible. +While the statement does nothing useful, +it satisfies Angular's requirement so that Angular will update the screen.It's easier to get to the input box with the template reference +variable than to go through the `$event` object. Here's a rewrite of the previous +`keyup` example that uses a template reference variable to get the user's input. + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-2'} + +A nice aspect of this approach is that the component gets clean data values from the view. +It no longer requires knowledge of the `$event` and its structure. +<a id="key-event"></a> +## Key event filtering (with `key.enter`) +The `(keyup)` event handler hears *every keystroke*. +Sometimes only the _Enter_ key matters, because it signals that the user has finished typing. +One way to reduce the noise would be to examine every `$event.keyCode` and take action only when the key is _Enter_. + +There's an easier way: bind to Angular's `keyup.enter` pseudo-event. +Then Angular calls the event handler only when the user presses _Enter_. + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-3'} + +Here's how it works. +<figure class='image-display'> + <img src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3"> </img> +</figure> + + +## On blur + +In the previous example, the current state of the input box +is lost if the user mouses away and clicks elsewhere on the page +without first pressing _Enter_. +The component's `value` property is updated only when the user presses _Enter_. + +To fix this issue, listen to both the _Enter_ key and the _blur_ event. + + +{@example 'user-input/ts/src/app/keyup.components.ts' region='key-up-component-4'} + + +## Put it all together +The previous page showed how to [display data](./displaying-data.html). +This page demonstrated event binding techniques. + +Now, put it all together in a micro-app +that can display a list of heroes and add new heroes to the list. +The user can add a hero by typing the hero's name in the input box and +clicking **Add**. + +<figure class='image-display'> + <img src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes"> </img> +</figure> + +Below is the "Little Tour of Heroes" component. + + +{@example 'user-input/ts/src/app/little-tour.component.ts' region='little-tour'} + +### Observations + +* **Use template variables to refer to elements** — +The `newHero` template variable refers to the `<input>` element. +You can reference `newHero` from any sibling or child of the `<input>` element. + +* **Pass values, not elements** — +Instead of passing the `newHero` into the component's `addHero` method, +get the input box value and pass *that* to `addHero`. + +* **Keep template statements simple** — +The `(blur)` event is bound to two JavaScript statements. +The first statement calls `addHero`. The second statement, `newHero.value=''`, +clears the input box after a new hero is added to the list. + +## Source code + +Following is all the code discussed in this page. +<md-tab-group> + + <md-tab label="click-me.component.ts"> + {@example 'user-input/ts/src/app/click-me.component.ts'} + </md-tab> + + + <md-tab label="keyup.components.ts"> + {@example 'user-input/ts/src/app/keyup.components.ts'} + </md-tab> + + + <md-tab label="loop-back.component.ts"> + {@example 'user-input/ts/src/app/loop-back.component.ts'} + </md-tab> + + + <md-tab label="little-tour.component.ts"> + {@example 'user-input/ts/src/app/little-tour.component.ts'} + </md-tab> + + +</md-tab-group> + + +## Summary + +You have mastered the basic primitives for responding to user input and gestures. + +These techniques are useful for small-scale demonstrations, but they +quickly become verbose and clumsy when handling large amounts of user input. +Two-way data binding is a more elegant and compact way to move +values between data entry fields and model properties. +The next page, `Forms`, explains how to write +two-way bindings with `NgModel`. \ No newline at end of file diff --git a/aio/content/guide/webpack.md b/aio/content/guide/webpack.md new file mode 100644 index 0000000000..c331b5d955 --- /dev/null +++ b/aio/content/guide/webpack.md @@ -0,0 +1,572 @@ +@title +Webpack: an introduction + +@intro +Create Angular applications with a Webpack based tooling + +@description + +<style> + h4 {font-size: 17px !important; text-transform: none !important;} + .syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; } + +</style> + +[**Webpack**](https://webpack.github.io/) is a popular module bundler, +a tool for bundling application source code in convenient _chunks_ +and for loading that code from a server into a browser. + +It's an excellent alternative to the *SystemJS* approach used elsewhere in the documentation. +This guide offers a taste of Webpack and explains how to use it with Angular applications. + +<a id="top"></a> +## Table of contents + +[What is Webpack?](#what-is-webpack) + + * [Entries and outputs](#entries-outputs) + * [Loaders](#loaders) + * [Plugins](#plugins) + +[Configuring Webpack](#configure-webpack) + + * [Common configuration](#common-configuration) + * [Development configuration](#development-configuration) + * [Production configuration](#production-configuration) + * [Test configuration](#test-configuration) + +[Trying it out](#try) + +[Conclusions](#conclusions) + +<a id="what-is-webpack"></a>## What is Webpack? + +Webpack is a powerful module bundler. +A _bundle_ is a JavaScript file that incorporate _assets_ that *belong* together and +should be served to the client in a response to a single file request. +A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file. + +Webpack roams over your application source code, +looking for `import` statements, building a dependency graph, and emitting one (or more) _bundles_. +With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files. + +You determine what Webpack does and how it does it with a JavaScript configuration file, `webpack.config.js`. + + +{@a entries-outputs} + +### Entries and outputs + +You supply Webpack with one or more *entry* files and let it find and incorporate the dependencies that radiate from those entries. +The one entry point file in this example is the application's root file, `src/app.ts`: + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='one-entry'} + +Webpack inspects that file and traverses its `import` dependencies recursively. + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='app-example'} + +It sees that you're importing *@angular/core* so it adds that to its dependency list for (potential) inclusion in the bundle. +It opens the *@angular/core* file and follows _its_ network of `import` statements until it has built the complete dependency graph from `app.ts` down. + +Then it **outputs** these files to the `app.js` _bundle file_ designated in configuration: + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='one-output'} + +This `app.js` output bundle is a single JavaScript file that contains the application source and its dependencies. +You'll load it later with a `<script>` tag in the `index.html`. + +#### Multiple bundles +You probably don't want one giant bundle of everything. +It's preferable to separate the volatile application app code from comparatively stable vendor code modules. + +Change the configuration so that it has two entry points, `app.ts` and `vendor.ts`: + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='two-entries'} + +Webpack constructs two separate dependency graphs +and emits *two* bundle files, one called `app.js` containing only the application code and +another called `vendor.js` with all the vendor dependencies. + +The `[name]` in the output name is a *placeholder* that a Webpack plugin replaces with the entry names, +`app` and `vendor`. Plugins are [covered later](#commons-chunk-plugin) in the guide. +To tell Webpack what belongs in the vendor bundle, +add a `vendor.ts` file that only imports the application's third-party modules: + +{@example 'webpack/ts/src/vendor.ts'} + + + +{@a loaders} + +### Loaders + +Webpack can bundle any kind of file: JavaScript, TypeScript, CSS, SASS, LESS, images, html, fonts, whatever. +Webpack _itself_ only understands JavaScript files. +Teach it to transform non-JavaScript file into their JavaScript equivalents with *loaders*. +Configure loaders for TypeScript and CSS as follows. + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='loaders'} + +As Webpack encounters `import` statements like these ... + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='imports'} + +... it applies the `test` RegEx patterns. When a pattern matches the filename, Webpack processes the file with the associated loader. + +The first `import` file matches the `.ts` pattern so Webpack processes it with the `awesome-typescript-loader`. +The imported file doesn't match the second pattern so its loader is ignored. + +The second `import` matches the second `.css` pattern for which you have *two* loaders chained by the (!) character. +Webpack applies chained loaders *right to left* so it applies +the `css` loader first (to flatten CSS `@import` and `url(...)` statements) and + then the `style` loader (to append the css inside *<style>* elements on the page). + + +{@a plugins} + +### Plugins + +Webpack has a build pipeline with well-defined phases. +Tap into that pipeline with plugins such as the `uglify` minification plugin: + + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='plugins'} + + + +{@a configure-webpack} + +## Configure Webpack + +After that brief orientation, you are ready to build your own Webpack configuration for Angular apps. + +Begin by setting up the development environment. + +Create a **new project folder** +<code-example language="sh" class="code-shell"> + mkdir angular-webpack + cd angular-webpack + +</code-example> + +Add these files to the root directory: + +<md-tab-group> + + <md-tab label="package.json"> + {@example 'webpack/ts/package.webpack.json'} + </md-tab> + + + <md-tab label="tsconfig.json"> + {@example 'webpack/ts/tsconfig.1.json'} + </md-tab> + + + <md-tab label="webpack.config.js"> + {@example 'webpack/ts/webpack.config.js'} + </md-tab> + + + <md-tab label="karma.conf.js"> + {@example 'webpack/ts/karma.webpack.conf.js'} + </md-tab> + + + <md-tab label="config/helpers.js"> + {@example 'webpack/ts/config/helpers.js'} + </md-tab> + + +</md-tab-group> + + +Many of these files should be familiar from other Angular documentation guides, +especially the [_Typescript configuration_](../guide/typescript-configuration.html) and +[_npm packages_](../guide/npm-packages.html) guides. + +Webpack, the plugins, and the loaders are also installed as packages. +They are listed in the updated `packages.json`. +Open a terminal window and (re)install the *npm* packages +<code-example language="sh" class="code-shell"> + npm install + +</code-example> + + + +{@a polyfills} + +### Polyfills + +You'll need polyfills to run an Angular application in most browsers as explained +in the [_Browser Support_](browser-support.html) guide. + +Polyfills should be bundled separately from the application and vendor bundles. +Add a `polyfills.ts` like this one to the `src/` folder. + + +{@example 'webpack/ts/src/polyfills.ts'} + + + +~~~ {.callout.is-critical} + + +<header> + Loading polyfills +</header> + +Load `zone.js` early within `polyfills.ts`, immediately after the other ES6 and metadata shims. + + +~~~ + +Because this bundle file will load first, `polyfills.ts` is also a good place to configure the browser environment +for production or development. + + +{@a common-configuration} + +### Common Configuration + +Developers typically have separate configurations for development, production, and test environments. +All three have a lot of configuration in common. + +Gather the common configuration in a file called `webpack.common.js`. + + +{@example 'webpack/ts/config/webpack.common.js'} + +### Inside _webpack.common.js_ +Webpack is a NodeJS-based tool that reads configuration from a JavaScript _commonjs_ module file. + +The configuration imports dependencies with `require` statements +and exports several objects as properties of a `module.exports` object. + +* [`entries`](#common-entries) - the entry-point files that define the bundles. +* [`resolve`](#common-resolve) - how to resolve file names when they lack extensions. +* [`module.rules`](#common-rules) - `module` is an object with `rules` for deciding how files are loaded. +* [`plugins`](#common-plugins) - creates instances of the plugins. + + +{@a common-entries} +#### _entries_ + +The first export is the *entries* object, described above: + + +{@example 'webpack/ts/config/webpack.common.js' region='entries'} + +This *entries* object defines the three bundles: + +* polyfills - the polyfills needed to run Angular applications in most modern browsers. +* vendor - the third-party dependencies such as Angular, lodash, and bootstrap.css. +* app - the application code. + + +{@a common-resolve} +#### _resolve_ extension-less imports + +The app will `import` dozens if not hundreds of JavaScript and TypeScript files. +You could write `import` statements with explicit extensions like this example: + +{@example 'webpack/ts-snippets/webpack.config.snippets.ts' region='single-import'} + +But most `import` statements don't mention the extension at all. +Tell Webpack to resolve extension-less file requests by looking for matching files with +`.ts` extension or `.js` extension (for regular JavaScript files and pre-compiled TypeScript files). + + +{@example 'webpack/ts/config/webpack.common.js' region='resolve'} + + +If Webpack should resolve extension-less files for styles and HTML, +add `.css` and `.html` to the list. + + +{@a common-rules} +#### _module.rules_ +Rules tell Webpack which loaders to use for each file (AKA _module_): + + +{@example 'webpack/ts/config/webpack.common.js' region='loaders'} + +* awesome-typescript-loader - a loader to transpile the Typescript code to ES5, guided by the `tsconfig.json` file +* angular2-template-loader - loads angular components' template and styles +* html - for component templates +* images/fonts - Images and fonts are bundled as well. +* css - The pattern matches application-wide styles; the second handles component-scoped styles (the ones specified in a component's `styleUrls` metadata property) +The first pattern excludes `.css` files within the `/src/app` directories where the component-scoped styles sit. +It includes only `.css` files located at or above `/src`; these are the application-wide styles. +The `ExtractTextPlugin` (described below) applies the `style` and `css` loaders to these files. + +The second pattern filters for component-scoped styles and loads them as strings via the `raw` loader — +which is what Angular expects to do with styles specified in a `styleUrls` metadata property. + +Multiple loaders can be chained using the array notation. + + +{@a common-plugins} +#### _plugins_ +Finally, create instances of three plugins: + + +{@example 'webpack/ts/config/webpack.common.js' region='plugins'} + + + +{@a commons-chunk-plugin} +#### *CommonsChunkPlugin* + +The `app.js` bundle should contain only application code. All vendor code belongs in the `vendor.js` bundle. + +Of course the application code `imports` vendor code. +Webpack itself is not smart enough to keep the vendor code out of the `app.js` bundle. +The `CommonsChunkPlugin` does that job. +The `CommonsChunkPlugin` identifies the hierarchy among three _chunks_: `app` -> `vendor` -> `polyfills`. +Where Webpack finds that `app` has shared dependencies with `vendor`, it removes them from `app`. +It would remove `polyfills` from `vendor` if they shared dependencies (which they don't). + + +{@a html-webpack-plugin} +#### *HtmlWebpackPlugin* + +Webpack generates a number of js and css files. +You _could_ insert them into the `index.html` _manually_. That would be tedious and error-prone. +Webpack can inject those scripts and links for you with the `HtmlWebpackPlugin`. + + +{@a environment-configuration} + +### Environment-specific configuration + +The `webpack.common.js` configuration file does most of the heavy lifting. +Create separate, environment-specific configuration files that build on `webpack.common` +by merging into it the peculiarities particular to the target environments. + +These files tend to be short and simple. + + +{@a development-configuration} + +### Development Configuration + +Here is the `webpack.dev.js` development configuration file. + + +{@example 'webpack/ts/config/webpack.dev.js'} + +The development build relies on the Webpack development server, configured near the bottom of the file. + +Although you tell Webpack to put output bundles in the `dist` folder, +the dev server keeps all bundles in memory; it doesn't write them to disk. +You won't find any files in the `dist` folder (at least not any generated from `this development build`). + + +The `HtmlWebpackPlugin` (added in `webpack.common.js`) use the *publicPath* and the *filename* settings to generate +appropriate <script> and <link> tags into the `index.html`. + +The CSS styles are buried inside the Javascript bundles by default. The `ExtractTextPlugin` extracts them into +external `.css` files that the `HtmlWebpackPlugin` inscribes as <link> tags into the `index.html`. + +Refer to the Webpack documentation for details on these and other configuration options in this file + +Grab the app code at the end of this guide and try: + +<code-example language="sh" class="code-shell"> + npm start + +</code-example> + + + +{@a production-configuration} + +### Production Configuration + +Configuration of a *production* build resembles *development* configuration ... with a few key changes. + + +{@example 'webpack/ts/config/webpack.prod.js'} + +You'll deploy the application and its dependencies to a real production server. +You won't deploy the artifacts needed only in development. + +Put the production output bundle files in the `dist` folder. + +Webpack generates file names with cache-busting hash. +Thanks to the `HtmlWebpackPlugin`, you don't have to update the `index.html` file when the hashes changes. + +There are additional plugins: + +* **NoEmitOnErrorsPlugin** - stops the build if there is an error. +* **UglifyJsPlugin** - minifies the bundles. +* **ExtractTextPlugin** - extracts embedded css as external files, adding cache-busting hash to the filename. +* **DefinePlugin** - use to define environment variables that you can reference within the application. +* **LoaderOptionsPlugins** - to override options of certain loaders. + +Thanks to the *DefinePlugin* and the `ENV` variable defined at top, you can enable Angular production mode like this: + + +{@example 'webpack/ts/src/main.ts' region='enable-prod'} + +Grab the app code at the end of this guide and try: + +<code-example language="sh" class="code-shell"> + npm run build + +</code-example> + + + +{@a test-configuration} + +### Test Configuration + +You don't need much configuration to run unit tests. +You don't need the loaders and plugins that you declared for your development and production builds. +You probably don't need to load and process the application-wide styles files for unit tests and doing so would slow you down; +you'll use the `null` loader for those CSS files. + +You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need. +But it might be simpler to start over with a completely fresh configuration. + + +{@example 'webpack/ts/config/webpack.test.js'} + +Reconfigure karma to use webpack to run the tests: + + +{@example 'webpack/ts/config/karma.conf.js'} + +You don't precompile the TypeScript; Webpack transpiles the Typescript files on the fly, in memory, and feeds the emitted JS directly to Karma. +There are no temporary files on disk. + +The `karma-test-shim` tells Karma what files to pre-load and +primes the Angular test framework with test versions of the providers that every app expects to be pre-loaded. + + +{@example 'webpack/ts/config/karma-test-shim.js'} + +Notice that you do _not_ load the application code explicitly. +You tell Webpack to find and load the test files (the files ending in `.spec.ts`). +Each spec file imports all — and only — the application source code that it tests. +Webpack loads just _those_ specific application files and ignores the other files that you aren't testing. +Grab the app code at the end of this guide and try: + +<code-example language="sh" class="code-shell"> + npm test + +</code-example> + +<a id="try"></a>## Trying it out + +Here is the source code for a small application that bundles with the +Webpack techniques covered in this guide. + +<md-tab-group> + + <md-tab label="src/index.html"> + {@example 'webpack/ts/src/index.html'} + </md-tab> + + + <md-tab label="src/main.ts"> + {@example 'webpack/ts/src/main.ts'} + </md-tab> + + + <md-tab label="public/css/styles.css"> + {@example 'webpack/ts/public/css/styles.css'} + </md-tab> + + +</md-tab-group> + + +<md-tab-group> + + <md-tab label="src/app/app.component.ts"> + {@example 'webpack/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="src/app/app.component.html"> + {@example 'webpack/ts/src/app/app.component.html'} + </md-tab> + + + <md-tab label="src/app/app.component.css"> + {@example 'webpack/ts/src/app/app.component.css'} + </md-tab> + + + <md-tab label="src/app/app.component.spec.ts"> + {@example 'webpack/ts/src/app/app.component.spec.ts'} + </md-tab> + + + <md-tab label="src/app/app.module.ts"> + {@example 'webpack/ts/src/app/app.module.ts'} + </md-tab> + + +</md-tab-group> + + +<p> + The <code>app.component.html</code> displays this downloadable Angular logo + <a href="https://raw.githubusercontent.com/angular/angular.io/master/public/resources/images/logos/angular2/angular.png" target="_blank"> + <img src="/resources/images/logos/angular2/angular.png" height="40px" title="download Angular logo"></a>. + +</p> + + + +{@a bundle-ts} +Here again are the TypeScript entry-point files that define the `polyfills` and `vendor` bundles. +<md-tab-group> + + <md-tab label="src/polyfills.ts"> + {@example 'webpack/ts/src/polyfills.ts'} + </md-tab> + + + <md-tab label="src/vendor.ts"> + {@example 'webpack/ts/src/vendor.ts'} + </md-tab> + + +</md-tab-group> + +<a id="highlights"></a>### Highlights: + +* There are no <script> or <link> tags in the `index.html`. +The `HtmlWebpackPlugin` inserts them dynamically at runtime. + +* The `AppComponent` in `app.component.ts` imports the application-wide css with a simple `import` statement. + +* The `AppComponent` itself has its own html template and css file. WebPack loads them with calls to `require()`. +Webpack stashes those component-scoped files in the `app.js` bundle too. +You don't see those calls in the source code; +they're added behind the scenes by the `angular2-template-loader` plug-in. + +* The `vendor.ts` consists of vendor dependency `import` statements that drive the `vendor.js` bundle. +The application imports these modules too; they'd be duplicated in the `app.js` bundle +if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `app.js`. +<a id="conclusions"></a>## Conclusions + +You've learned just enough Webpack to configurate development, test and production builds +for a small Angular application. + +_You could always do more_. Search the web for expert advice and expand your Webpack knowledge. + +[Back to top](#top) \ No newline at end of file diff --git a/aio/content/tutorial/index.md b/aio/content/tutorial/index.md new file mode 100644 index 0000000000..cb4270a74e --- /dev/null +++ b/aio/content/tutorial/index.md @@ -0,0 +1,82 @@ +@title +Tutorial: Tour of Heroes + +@intro +The Tour of Heroes tutorial takes you through the steps of creating an Angular application in TypeScript. + +@description +Our grand plan for this tutorial is to build an app to help a staffing agency manage its stable of heroes. +Even heroes need to find work. + +Of course we'll only make a little progress in this tutorial. What we do build will +have many of the features we expect to find in a full-blown, data-driven application: acquiring and displaying +a list of heroes, editing a selected hero's detail, and navigating among different +views of heroic data. + +The Tour of Heroes covers the core fundamentals of Angular. +We’ll use built-in directives to show/hide elements and display lists of hero data. +We’ll create a component to display hero details and another to show an array of heroes. +We'll use one-way data binding for read-only data. We'll add editable fields to update a model +with two-way data binding. We'll bind component methods to user events like key strokes and clicks. +We’ll learn to select a hero from a master list and edit that hero in the details view. We'll +format data with pipes. We'll create a shared service to assemble our heroes. And we'll use routing to navigate among different views and their components. + +We’ll learn enough core Angular to get started and gain confidence that +Angular can do whatever we need it to do. +We'll be covering a lot of ground at an introductory level but we’ll find plenty of links +to chapters with greater depth. + +Run the <live-example name="toh-6"></live-example>. + +## The End Game + +Here's a visual idea of where we're going in this tour, beginning with the "Dashboard" +view and our most heroic heroes: + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard"> </img> +</figure> + +Above the dashboard are two links ("Dashboard" and "Heroes"). +We could click them to navigate between this Dashboard and a Heroes view. + +Instead we click the dashboard hero named "Magneta" and the router takes us to a "Hero Details" view +of that hero where we can change the hero's name. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/hero-details-1.png' alt="Details of hero in app"> </img> +</figure> + +Clicking the "Back" button would return us to the "Dashboard". +Links at the top can take us to either of the main views. +We'll click "Heroes". The app takes to the "Heroes" master list view. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app"> </img> +</figure> + +We click a different hero and the readonly mini-detail beneath the list reflects our new choice. + +We click the "View Details" button to drill into the +editable details of our selected hero. + +The following diagram captures all of our navigation options. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img> +</figure> + +Here's our app in action + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action"> </img> +</figure> + + +## Up Next + +We’ll build this Tour of Heroes together, step by step. +We'll motivate each step with a requirement that we've +met in countless applications. Everything has a reason. + +And we’ll meet many of the core fundamentals of Angular along the way. \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt1.md b/aio/content/tutorial/toh-pt1.md new file mode 100644 index 0000000000..79bebf680d --- /dev/null +++ b/aio/content/tutorial/toh-pt1.md @@ -0,0 +1,229 @@ +@title +The Hero Editor + +@intro +We build a simple hero editor + +@description +## Setup to develop locally +Real application development takes place in a local development environment like your machine. + +Follow the [setup](../guide/setup.html) instructions for creating a new project +named <ngio-ex path="angular-tour-of-heroes"></ngio-ex> +after which the file structure should look like this: + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +When we're done with this first episode, the app runs like this <live-example></live-example>. + +## Keep the app transpiling and running +We want to start the TypeScript compiler, have it watch for changes, and start our server. +Do this by entering the following command in the terminal window. + + +<code-example language="sh" class="code-shell"> + npm start + +</code-example> + +This command runs the compiler in watch mode, starts the server, launches the app in a browser, +and keeps the app running while we continue to build the Tour of Heroes. + +## Show our Hero +We want to display Hero data in our app + +Update the `AppComponent` so it has two properties:   a `title` property for the application name and a `hero` property +for a hero named "Windstorm". + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='app-component-1'} + +Now update the template in the `@Component` decoration with data bindings to these new properties. + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='show-hero'} + +The browser should refresh and display our title and hero. + +The double curly braces tell our app to read the `title` and `hero` properties from the component and render them. +This is the "interpolation" form of one-way data binding. +Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html).### Hero object + +At the moment, our hero is just a name. Our hero needs more properties. +Let's convert the `hero` from a literal string to a class. + +Create a `Hero` class with `id` and `name` properties. +For now put this near the top of the `app.component.ts` file, just below the import statement. + + +{@example 'toh-1/ts/src/app/app.component.ts' region='hero-class-1'} + +Now that we have a `Hero` class, let’s refactor our component’s `hero` property to be of type `Hero`. +Then initialize it with an id of `1` and the name, "Windstorm". + + +{@example 'toh-1/ts/src/app/app.component.ts' region='hero-property-1'} + +Because we changed the hero from a string to an object, +we update the binding in the template to refer to the hero’s `name` property. + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='show-hero-2'} + +The browser refreshes and continues to display our hero’s name. + +### Adding more HTML +Displaying a name is good, but we want to see all of our hero’s properties. +We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`. + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='show-hero-properties'} + +Uh oh, our template string is getting long. We better take care of that to avoid the risk of making a typo in the template. + +### Multi-line template strings + +We could make a more readable template with string concatenation +but that gets ugly fast, it is harder to read, and +it is easy to make a spelling error. Instead, +let’s take advantage of the template strings feature +in ES2015 and TypeScript to maintain our sanity. + +Change the quotes around the template to back-ticks and +put the `<h1>`, `<h2>` and `<div>` elements on their own lines. + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='multi-line-strings'} + + +## Editing Our Hero + +We want to be able to edit the hero name in a textbox. + +Refactor the hero name `<label>` with `<label>` and `<input>` elements as shown below: + + +{@example 'toh-1/ts-snippets/app.component.snippets.pt1.ts' region='editing-Hero'} + +We see in the browser that the hero’s name does appear in the `<input>` textbox. +But something doesn’t feel right. +When we change the name, we notice that our change +is not reflected in the `<h2>`. We won't get the desired behavior +with a one-way binding to `<input>`. + +### Two-Way Binding + +We intend to display the name of the hero in the `<input>`, change it, +and see those changes wherever we bind to the hero’s name. +In short, we want two-way data binding. + +Before we can use two-way data binding for **form inputs**, we need to import the `FormsModule` +package in our Angular module. We add it to the `NgModule` decorator's `imports` array. This array contains the list +of external modules used by our application. +Now we have included the forms package which includes `ngModel`. + + +{@example 'toh-1/ts/src/app/app.module.ts'} + + +Learn more about the `FormsModule` and `ngModel` in the +[Forms](../guide/forms.html#ngModel) and +[Template Syntax](../guide/template-syntax.html#ngModel) chapters. +Let’s update the template to use the **`ngModel`** built-in directive for two-way binding. + +Replace the `<input>` with the following HTML + +<code-example language="html"> + <input [(ngModel)]="hero.name" placeholder="name"> + +</code-example> + +The browser refreshes. We see our hero again. We can edit the hero’s name and +see the changes reflected immediately in the `<h2>`. + +## The Road We’ve Travelled +Let’s take stock of what we’ve built. + +* Our Tour of Heroes uses the double curly braces of interpolation (a kind of one-way data binding) +to display the application title and properties of a `Hero` object. +* We wrote a multi-line template using ES2015’s template strings to make our template readable. +* We can both display and change the hero’s name after adding a two-way data binding to the `<input>` element +using the built-in `ngModel` directive. +* The `ngModel` directive also propagates changes to every other binding of the `hero.name`. + +Run the <live-example></live-example> for this part. + +Here's the complete `app.component.ts` as it stands now: + + +{@example 'toh-1/ts/src/app/app.component.ts' region='pt1'} + + +## The Road Ahead +Our Tour of Heroes only displays one hero and we really want to display a list of heroes. +We also want to allow the user to select a hero and display their details. +We’ll learn more about how to retrieve lists, bind them to the +template, and allow a user to select a hero in the +[next tutorial chapter](./toh-pt2.html). \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt2.md b/aio/content/tutorial/toh-pt2.md new file mode 100644 index 0000000000..a7cee940b2 --- /dev/null +++ b/aio/content/tutorial/toh-pt2.md @@ -0,0 +1,356 @@ +@title +Master/Detail + +@intro +We build a master/detail page with a list of heroes + +@description +Our story needs more heroes. +We’ll expand our Tour of Heroes app to display a list of heroes, +allow the user to select a hero, and display the hero’s details. + +Run the <live-example></live-example> for this part. + +Let’s take stock of what we’ll need to display a list of heroes. +First, we need a list of heroes. We want to display those heroes in the view’s template, +so we’ll need a way to do that. + +## Where We Left Off +Before we continue with Part 2 of the Tour of Heroes, +let’s verify we have the following structure after [Part 1](./toh-pt1.html). +If not, we’ll need to go back to Part 1 and figure out what we missed. + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +### Keep the app transpiling and running +We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing + +<code-example language="sh" class="code-shell"> + npm start + +</code-example> + +This will keep the application running while we continue to build the Tour of Heroes. + +## Displaying Our Heroes +### Creating heroes +Let’s create an array of ten heroes. + + +{@example 'toh-2/ts/src/app/app.component.ts' region='hero-array'} + +The `HEROES` array is of type `Hero`, the class defined in part one, +to create an array of heroes. +We aspire to fetch this list of heroes from a web service, but let’s take small steps +first and display mock heroes. + +### Exposing heroes +Let’s create a public property in `AppComponent` that exposes the heroes for binding. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='hero-array-1'} + +We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array. +We could have defined the heroes list here in this component class. +But we know that ultimately we’ll get the heroes from a data service. +Because we know where we are heading, it makes sense to separate the hero data +from the class implementation from the start.### Displaying heroes in a template +Our component has `heroes`. Let’s create an unordered list in our template to display them. +We’ll insert the following chunk of HTML below the title and above the hero details. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='heroes-template-1'} + +Now we have a template that we can fill with our heroes. + +### Listing heroes with ngFor + +We want to bind the array of `heroes` in our component to our template, iterate over them, +and display them individually. +We’ll need some help from Angular to do this. Let’s do this step by step. + +First modify the `<li>` tag by adding the built-in directive `*ngFor`. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='heroes-ngfor-1'} + + + +~~~ {.alert.is-critical} + +The leading asterisk (`*`) in front of `ngFor` is a critical part of this syntax. + + +~~~ + + +The (`*`) prefix to `ngFor` indicates that the `<li>` element and its children +constitute a master template. + +The `ngFor` directive iterates over the `heroes` array returned by the `AppComponent.heroes` property +and stamps out instances of this template. + +The quoted text assigned to `ngFor` means +“*take each hero in the `heroes` array, store it in the local `hero` variable, +and make it available to the corresponding template instance*”. + +The `let` keyword before "hero" identifies `hero` as a template input variable. +We can reference this variable within the template to access a hero’s properties. + +Learn more about `ngFor` and template input variables in the +[Displaying Data](../guide/displaying-data.html#ngFor) and +[Template Syntax](../guide/template-syntax.html#ngFor) chapters. +Now we insert some content between the `<li>` tags +that uses the `hero` template variable to display the hero’s properties. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='ng-for'} + +When the browser refreshes, we see a list of heroes! + +### Styling our heroes +Our list of heroes looks pretty bland. +We want to make it visually obvious to a user which hero we are hovering over and which hero is selected. + +Let’s add some styles to our component by setting the `styles` property on the `@Component` decorator +to the following CSS classes: + + +{@example 'toh-2/ts/src/app/app.component.ts' region='styles'} + +Notice that we again use the back-tick notation for multi-line strings. + +That's a lot of styles! We can put them inline as shown here, or we can move them out to their own file which will make it easier to code our component. +We'll do this in a later chapter. For now let's keep rolling. + +When we assign styles to a component they are scoped to that specific component. +Our styles will only apply to our `AppComponent` and won't "leak" to the outer HTML. + +Our template for displaying the heroes should now look like this: + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='heroes-styled'} + + +## Selecting a Hero +We have a list of heroes and we have a single hero displayed in our app. +The list and the single hero are not connected in any way. +We want the user to select a hero from our list, and have the selected hero appear in the details view. +This UI pattern is widely known as "master-detail". +In our case, the master is the heroes list and the detail is the selected hero. + +Let’s connect the master to the detail through a `selectedHero` component property bound to a click event. + +### Click event +We modify the `<li>` by inserting an Angular event binding to its click event. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='selectedHero-click'} + +Focus on the event binding +<code-example> + (click)="onSelect(hero)" +</code-example> + +The parenthesis identify the `<li>` element’s `click` event as the target. +The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`, +passing the template input variable `hero` as an argument. +That’s the same `hero` variable we defined previously in the `ngFor`. +Learn more about Event Binding in the +[User Input](../guide/user-input.html) and +[Templating Syntax](../guide/template-syntax.html#event-binding) chapters.### Add the click handler +Our event binding refers to an `onSelect` method that doesn’t exist yet. +We’ll add that method to our component now. + +What should that method do? It should set the component’s selected hero to the hero that the user clicked. + +Our component doesn’t have a “selected hero” yet either. We’ll start there. + +### Expose the selected hero + +We no longer need the static `hero` property of the `AppComponent`. +**Replace** it with this simple `selectedHero` property: + + +{@example 'toh-2/ts/src/app/app.component.ts' region='selected-hero'} + +We’ve decided that none of the heroes should be selected before the user picks a hero so +we won’t initialize the `selectedHero` as we were doing with `hero`. + +Now **add an `onSelect` method** that sets the `selectedHero` property to the `hero` the user clicked. + +{@example 'toh-2/ts/src/app/app.component.ts' region='on-select'} + +We will be showing the selected hero's details in our template. +At the moment, it is still referring to the old `hero` property. +Let’s fix the template to bind to the new `selectedHero` property. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='selectedHero-details'} + +### Hide the empty detail with ngIf + +When our app loads we see a list of heroes, but a hero is not selected. +The `selectedHero` is `undefined`. +That’s why we'll see the following error in the browser’s console: + +<code-example format="nocode"> + EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null] + +</code-example> + +Remember that we are displaying `selectedHero.name` in the template. +This name property does not exist because `selectedHero` itself is undefined. + +We'll address this problem by keeping the hero detail out of the DOM until there is a selected hero. + +We wrap the HTML hero detail content of our template with a `<div>`. +Then we add the `ngIf` built-in directive and set it to the `selectedHero` property of our component. + + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='ng-if'} + + + +~~~ {.alert.is-critical} + +Remember that the leading asterisk (`*`) in front of `ngIf` is +a critical part of this syntax. + +~~~ + +When there is no `selectedHero`, the `ngIf` directive removes the hero detail HTML from the DOM. +There will be no hero detail elements and no bindings to worry about. + +When the user picks a hero, `selectedHero` becomes "truthy" and +`ngIf` puts the hero detail content into the DOM and evaluates the nested bindings. +`ngIf` and `ngFor` are called “structural directives” because they can change the +structure of portions of the DOM. +In other words, they give structure to the way Angular displays content in the DOM. + +Learn more about `ngIf`, `ngFor` and other structural directives in the +[Structural Directives](../guide/structural-directives.html) and +[Template Syntax](../guide/template-syntax.html#directives) chapters. +The browser refreshes and we see the list of heroes but not the selected hero detail. +The `ngIf` keeps it out of the DOM as long as the `selectedHero` is undefined. +When we click on a hero in the list, the selected hero displays in the hero details. +Everything is working as we expect. + +### Styling the selection + +We see the selected hero in the details area below but we can’t quickly locate that hero in the list above. +We can fix that by applying the `selected` CSS class to the appropriate `<li>` in the master list. +For example, when we select Magneta from the heroes list, +we can make it pop out visually by giving it a subtle background color as shown here. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/heroes-list-selected.png' alt="Selected hero"> </img> +</figure> + +We’ll add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`. + +The key is the name of the CSS class (`selected`). The value is `true` if the two heroes match and `false` otherwise. +We’re saying “*apply the `selected` class if the heroes match, remove it if they don’t*”. + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='class-selected-1'} + +Notice in the template that the `class.selected` is surrounded in square brackets (`[]`). +This is the syntax for a **property binding**, a binding in which data flows one way +from the data source (the expression `hero === selectedHero`) to a property of `class`. + +{@example 'toh-2/ts-snippets/app.component.snippets.pt2.ts' region='class-selected-2'} + + +Learn more about [property bindings](../guide/template-syntax.html#property-binding) +in the Template Syntax chapter. +The browser reloads our app. +We select the hero Magneta and the selection is clearly identified by the background color. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app"> </img> +</figure> + +We select a different hero and the tell-tale color switches to that hero. + +Here's the complete `app.component.ts` as it stands now: + + +{@example 'toh-2/ts/src/app/app.component.ts'} + + +## The Road We’ve Travelled +Here’s what we achieved in this chapter: + +* Our Tour of Heroes now displays a list of selectable heroes +* We added the ability to select a hero and show the hero’s details +* We learned how to use the built-in directives `ngIf` and `ngFor` in a component’s template + +Run the <live-example></live-example> for this part. + +### The Road Ahead +Our Tour of Heroes has grown, but it’s far from complete. +We can't put the entire app into a single component. +We need to break it up into sub-components and teach them to work together +as we learn in the [next chapter](toh-pt3.html). \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt3.md b/aio/content/tutorial/toh-pt3.md new file mode 100644 index 0000000000..c624eff42d --- /dev/null +++ b/aio/content/tutorial/toh-pt3.md @@ -0,0 +1,365 @@ +@title +Multiple Components + +@intro +We refactor the master/detail view into separate components + +@description +Our app is growing. +Use cases are flowing in for reusing components, passing data to components, and creating more reusable assets. Let's separate the heroes list from the hero details and make the details component reusable. + +Run the <live-example></live-example> for this part. + +## Where We Left Off +Before we continue with our Tour of Heroes, let’s verify we have the following structure. If not, we’ll need to go back and follow the previous chapters. + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +### Keep the app transpiling and running +We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing + +<code-example language="sh" class="code-shell"> + npm start + +</code-example> + +This will keep the application running while we continue to build the Tour of Heroes. + +## Making a Hero Detail Component +Our heroes list and our hero details are in the same component in the same file. +They're small now but each could grow. +We are sure to receive new requirements for one and not the other. +Yet every change puts both components at risk and doubles the testing burden without benefit. +If we had to reuse the hero details elsewhere in our app, +the heroes list would tag along for the ride. + +Our current component violates the +[Single Responsibility Principle](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html). +It's only a tutorial but we can still do things right — +especially if doing them right is easy and we learn how to build Angular apps in the process. + +Let’s break the hero details out into its own component. + +### Separating the Hero Detail Component +Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows. + + +{@example 'toh-3/ts/src/app/hero-detail.component.ts' region='v1'} + + +### Naming conventions +We like to identify at a glance which classes are components and which files contain components. + +Notice that we have an `AppComponent` in a file named `app.component.ts` and our new +`HeroDetailComponent` is in a file named `hero-detail.component.ts`. + +All of our component names end in "Component". All of our component file names end in ".component". + +We spell our file names in lower **[dash case](../guide/glossary.html#dash-case)** +(AKA **[kebab-case](../guide/glossary.html#kebab-case)**) so we don't worry about +case sensitivity on the server or in source control. + +<!-- TODO +.l-sub-section + :marked + Learn more about naming conventions in the chapter [Naming Conventions] +:marked +-->We begin by importing the `Component` and `Input` decorators from Angular because we're going to need them soon. + +We create metadata with the `@Component` decorator where we +specify the selector name that identifies this component's element. +Then we export the class to make it available to other components. + +When we finish here, we'll import it into `AppComponent` and create a corresponding `<my-hero-detail>` element.#### Hero Detail Template +At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`. +Let’s **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`. + +We previously bound to the `selectedHero.name` property of the `AppComponent`. +Our `HeroDetailComponent` will have a `hero` property, not a `selectedHero` property. +So we replace `selectedHero` with `hero` everywhere in our new template. That's our only change. +The result looks like this: + + +{@example 'toh-3/ts/src/app/hero-detail.component.ts' region='template'} + +Now our hero detail layout exists only in the `HeroDetailComponent`. + +#### Add the *hero* property +Let’s add that `hero` property we were talking about to the component class. + +{@example 'toh-3/ts/src/app/hero-detail.component.ts' region='hero'} + +Uh oh. We declared the `hero` property as type `Hero` but our `Hero` class is over in the `app.component.ts` file. +We have two components, each in their own file, that need to reference the `Hero` class. + +We solve the problem by relocating the `Hero` class from `app.component.ts` to its own `hero.ts` file. + + +{@example 'toh-3/ts/src/app/hero.ts'} + +We export the `Hero` class from `hero.ts` because we'll need to reference it in both component files. +Add the following import statement near the top of **both `app.component.ts` and `hero-detail.component.ts`**. + + +{@example 'toh-3/ts/src/app/hero-detail.component.ts' region='hero-import'} + +#### The *hero* property is an ***input*** + +The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`! + +The `AppComponent` knows which hero to show: the hero that the user selected from the list. +The user's selection is in its `selectedHero` property. + +We will soon update the `AppComponent` template so that it binds its `selectedHero` property +to the `hero` property of our `HeroDetailComponent`. The binding *might* look like this: +<code-example language="html"> + <my-hero-detail [hero]="selectedHero"></my-hero-detail> +</code-example> + +Notice that the `hero` property is the ***target*** of a property binding — it's in square brackets to the left of the (=). + +Angular insists that we declare a ***target*** property to be an ***input*** property. +If we don't, Angular rejects the binding and throws an error. +We explain input properties in more detail [here](../guide/attribute-directives.html#why-input) +where we also explain why *target* properties require this special treatment and +*source* properties do not.There are a couple of ways we can declare that `hero` is an *input*. +We'll do it the way we *prefer*, by annotating the `hero` property with the `@Input` decorator that we imported earlier. + +{@example 'toh-3/ts/src/app/hero-detail.component.ts' region='hero-input'} + + +Learn more about the `@Input()` decorator in the +[Attribute Directives](../guide/attribute-directives.html#input) chapter. + +## Refresh the AppModule +We return to the `AppModule`, the application's root module, and teach it to use the `HeroDetailComponent`. + +We begin by importing the `HeroDetailComponent` so we can refer to it. + + +{@example 'toh-3/ts/src/app/app.module.ts' region='hero-detail-import'} + +Then we add `HeroDetailComponent` to the `NgModule` decorator's `declarations` array. +This array contains the list of all components, pipes, and directives that we created +and that belong in our application's module. + + +{@example 'toh-3/ts/src/app/app.module.ts' region='declarations'} + + +## Refresh the AppComponentNow that the application knows about our `HeroDetailComponent`, +find the location in the `AppComponent` template where we removed the *Hero Detail* content +and add an element tag that represents the `HeroDetailComponent`. +<code-example language="html"> + <my-hero-detail></my-hero-detail> +</code-example> + + +*my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata.The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent` +to the `HeroDetailComponent` element's `hero` property like this: +<code-example language="html"> + <my-hero-detail [hero]="selectedHero"></my-hero-detail> +</code-example> + +The `AppComponent`’s template should now look like this + + +{@example 'toh-3/ts/src/app/app.component.ts' region='hero-detail-template'} + +Thanks to the binding, the `HeroDetailComponent` should receive the hero from the `AppComponent` and display that hero's detail beneath the list. +The detail should update every time the user picks a new hero. +### It works! +When we view our app in the browser we see the list of heroes. +When we select a hero we can see the selected hero’s details. + +What's fundamentally new is that we can use this `HeroDetailComponent` +to show hero details anywhere in the app. + +We’ve created our first reusable component! + +### Reviewing the App Structure +Let’s verify that we have the following structure after all of our good refactoring in this chapter: + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + hero.ts + </aio-file> + + + <aio-file> + hero-detail.component.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +Here are the code files we discussed in this chapter. + +<md-tab-group> + + <md-tab label="src/app/hero-detail.component.ts"> + {@example 'toh-3/ts/src/app/hero-detail.component.ts'} + </md-tab> + + + <md-tab label="src/app/app.component.ts"> + {@example 'toh-3/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="src/app/hero.ts"> + {@example 'toh-3/ts/src/app/hero.ts'} + </md-tab> + + + <md-tab label="src/app/app.module.ts"> + {@example 'toh-3/ts/src/app/app.module.ts'} + </md-tab> + + +</md-tab-group> + + +## The Road We’ve Travelled +Let’s take stock of what we’ve built. + +* We created a reusable component +* We learned how to make a component accept input +* We learned to declare the application directives we need in an Angular module. We +list the directives in the `NgModule` decorator's `declarations` array. +* We learned to bind a parent component to a child component. + +Run the <live-example></live-example> for this part. + +## The Road Ahead +Our Tour of Heroes has become more reusable with shared components. + +We're still getting our (mock) data within the `AppComponent`. +That's not sustainable. +We should refactor data access to a separate service +and share it among the components that need data. + +We’ll learn to create services in the [next tutorial](toh-pt4.html) chapter. \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt4.md b/aio/content/tutorial/toh-pt4.md new file mode 100644 index 0000000000..54ff8a5645 --- /dev/null +++ b/aio/content/tutorial/toh-pt4.md @@ -0,0 +1,473 @@ +@title +Services + +@intro +We create a reusable service to manage our hero data calls + +@description +The Tour of Heroes is evolving and we anticipate adding more components in the near future. + +Multiple components will need access to hero data and we don't want to copy and +paste the same code over and over. +Instead, we'll create a single reusable data service and learn to +inject it in the components that need it. + +Refactoring data access to a separate service keeps the component lean and focused on supporting the view. +It also makes it easier to unit test the component with a mock service. + +Because data services are invariably asynchronous, +we'll finish the chapter with a **!{_Promise}**-based version of the data service. + +Run the <live-example></live-example> for this part. + +## Where We Left Off +Before we continue with our Tour of Heroes, let’s verify we have the following structure. +If not, we’ll need to go back and follow the previous chapters. + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + hero.ts + </aio-file> + + + <aio-file> + hero-detail.component.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +### Keep the app transpiling and running +Open a terminal/console window. +Start the TypeScript compiler, watch for changes, and start our server by entering the command: + +<code-example language="sh" class="code-shell"> + npm start + +</code-example> + +The application runs and updates automatically as we continue to build the Tour of Heroes. + +## Creating a Hero Service +Our stakeholders have shared their larger vision for our app. +They tell us they want to show the heroes in various ways on different pages. +We already can select a hero from a list. +Soon we'll add a dashboard with the top performing heroes and create a separate view for editing hero details. +All three views need hero data. + +At the moment the `AppComponent` defines mock heroes for display. +We have at least two objections. +First, defining heroes is not the component's job. +Second, we can't easily share that list of heroes with other components and views. + +We can refactor this hero data acquisition business to a single service that provides heroes, and +share that service with all components that need heroes. + +### Create the HeroService +Create a file in the `app` folder called `hero.service.ts`. +We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`. +If the service name were multi-word, we'd spell the base filename in lower [dash-case](../guide/glossary.html#dash-case). +The `SpecialSuperHeroService` would be defined in the `special-super-hero.service.ts` file.We name the class `HeroService` and export it for others to import. + + +{@example 'toh-4/ts/src/app/hero.service.1.ts' region='empty-class'} + +### Injectable Services +Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator. + +~~~ {.callout.is-helpful} + +**Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose. + +~~~ + +TypeScript sees the `@Injectable()` decorator and emits metadata about our service, +metadata that Angular may need to inject other dependencies into this service. + +The `HeroService` doesn't have any dependencies *at the moment*. Add the decorator anyway. +It is a "best practice" to apply the `@Injectable()` decorator ​*from the start*​ +both for consistency and for future-proofing. +### Getting Heroes +Add a `getHeroes` method stub. + +{@example 'toh-4/ts/src/app/hero.service.1.ts' region='getHeroes-stub'} + +We're holding back on the implementation for a moment to make an important point. + +The consumer of our service doesn't know how the service gets the data. +Our `HeroService` could get `Hero` data from anywhere. +It could get the data from a web service or local storage +or from a mock data source. + +That's the beauty of removing data access from the component. +We can change our minds about the implementation as often as we like, +for whatever reason, without touching any of the components that need heroes. + + +### Mock Heroes +We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either. +We'll move the mock data to its own file. + +Cut the `HEROES` array from `app.component.ts` and paste it to a new file in the `app` folder named `mock-heroes.ts`. +We copy the `import {Hero} ...` statement as well because the heroes array uses the `Hero` class. + + +{@example 'toh-4/ts/src/app/mock-heroes.ts'} + +We export the `HEROES` constant so we can import it elsewhere — such as our `HeroService`. + +Meanwhile, back in `app.component.ts` where we cut away the `HEROES` array, +we leave behind an uninitialized `heroes` property: + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='heroes-prop'} + +### Return Mocked Heroes +Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method. +Our `HeroService` looks like this: + +{@example 'toh-4/ts/src/app/hero.service.1.ts' region='full'} + +### Use the Hero Service +We're ready to use the `HeroService` in other components starting with our `AppComponent`. + +We begin, as usual, by importing the thing we want to use, the `HeroService`.Importing the service allows us to *reference* it in our code. +How should the `AppComponent` acquire a runtime concrete `HeroService` instance? + +### Do we *new* the *HeroService*? No way! +We could create a new instance of the `HeroService` with `new` like this: + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='new-service'} + +That's a bad idea for several reasons including + +* Our component has to know how to create a `HeroService`. +If we ever change the `HeroService` constructor, +we'll have to find every place we create the service and fix it. +Running around patching code is error prone and adds to the test burden. + +* We create a new service each time we use `new`. +What if the service should cache heroes and share that cache with others? +We couldn't do that. + +* We're locking the `AppComponent` into a specific implementation of the `HeroService`. +It will be hard to switch implementations for different scenarios. +Can we operate offline? +Will we need different mocked versions under test? +Not easy. + +*What if ... what if ... Hey, we've got work to do!* + +We get it. Really we do. +But it is so ridiculously easy to avoid these problems that there is no excuse for doing it wrong. + +### Inject the *HeroService* + +Two lines replace the one line that created with *new*: +1. We add a constructor that also defines a private property. +1. We add to the component's `providers` metadata. + +Here's the constructor: + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='ctor'} + +The constructor itself does nothing. The parameter simultaneously +defines a private `heroService` property and identifies it as a `HeroService` injection site.Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`. + +Learn more about Dependency Injection in the [Dependency Injection](../guide/dependency-injection.html) chapter.The *injector* does not know yet how to create a `HeroService`. +If we ran our code now, Angular would fail with an error: +<code-example format="nocode"> + EXCEPTION: No provider for HeroService! (AppComponent -> HeroService) +</code-example> + +We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**. +Do that by adding the following `providers` array property to the bottom of the component metadata +in the `@Component` call. +The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`. +The `AppComponent` can use that service to get heroes and so can every child component of its component tree. + +{@a child-component} +### *getHeroes* in the *AppComponent* +We've got the service in a `heroService` private variable. Let's use it. + +We pause to think. We can call the service and get the data in one line. + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='get-heroes'} + +We don't really need a dedicated method to wrap one line. We write it anyway:<a id="oninit"></a>### The *ngOnInit* Lifecycle Hook +`AppComponent` should fetch and display heroes without a fuss. +Where do we call the `getHeroes` method? In a constructor? We do *not*! + +Years of experience and bitter tears have taught us to keep complex logic out of the constructor, +especially anything that might call a server as a data access method is sure to do. + +The constructor is for simple initializations like wiring constructor parameters to properties. +It's not for heavy lifting. We should be able to create a component in a test and not worry that it +might do real work — like calling a server! — before we tell it to do so. + +If not the constructor, something has to call `getHeroes`. + +Angular will call it if we implement the Angular **ngOnInit** *Lifecycle Hook*. +Angular offers a number of interfaces for tapping into critical moments in the component lifecycle: +at creation, after each change, and at its eventual destruction. + +Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time. +Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.Here's the essential outline for the `OnInit` interface: + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='on-init'} + +We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it +at the right time. In our case, we initialize by calling `getHeroes`.Our application should be running as expected, showing a list of heroes and a hero detail view +when we click on a hero name. + +We're getting closer. But something isn't quite right. + +<a id="async"></a> +## Async Services and !{_Promise}s +Our `HeroService` returns a list of mock heroes immediately. +Its `getHeroes` signature is synchronous + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='get-heroes'} + +Ask for heroes and they are there in the returned result. + +Someday we're going to get heroes from a remote server. We don’t call http yet, but we aspire to in later chapters. + +When we do, we'll have to wait for the server to respond and we won't be able to block the UI while we wait, +even if we want to (which we shouldn't) because the browser won't block. + +We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method. + +We'll use *!{_Promise}s*. + +### The Hero Service makes a !{_Promise} + +A **!{_Promise}** is ... well it's a promise to call us back later when the results are ready. +We ask an asynchronous service to do some work and give it a callback function. +It does that work (somewhere) and eventually it calls our function with the results of the work or an error. +We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.Update the `HeroService` with this !{_Promise}-returning `getHeroes` method: + +{@example 'toh-4/ts/src/app/hero.service.ts' region='get-heroes'} + +We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server, +by returning an **immediately resolved !{_Promise}** with our mock heroes as the result. + +### Act on the !{_Promise} +Returning to the `AppComponent` and its `getHeroes` method, we see that it still looks like this: + +{@example 'toh-4/ts/src/app/app.component.1.ts' region='getHeroes'} + +As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes. + +We have to change our implementation to *act on the !{_Promise} when it resolves*. +When the !{_Promise} resolves successfully, *then* we will have heroes to display. + +We pass our callback function as an argument to the !{_Promise}'s **then** method: + +{@example 'toh-4/ts/src/app/app.component.ts' region='get-heroes'} + + +The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) +in the callback is more succinct than the equivalent function expression and gracefully handles *this*.Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it! + +Our app should still be running, still showing a list of heroes, and still +responding to a name selection with a detail view. +Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.### Review the App Structure +Let’s verify that we have the following structure after all of our good refactoring in this chapter: + +<aio-filetree> + + <aio-folder> + angular-tour-of-heroes + <aio-folder> + src + <aio-folder> + app + <aio-file> + app.component.ts + </aio-file> + + + <aio-file> + app.module.ts + </aio-file> + + + <aio-file> + hero.ts + </aio-file> + + + <aio-file> + hero-detail.component.ts + </aio-file> + + + <aio-file> + hero.service.ts + </aio-file> + + + <aio-file> + mock-heroes.ts + </aio-file> + + + </aio-folder> + + + <aio-file> + main.ts + </aio-file> + + + <aio-file> + index.html + </aio-file> + + + <aio-file> + styles.css + </aio-file> + + + <aio-file> + systemjs.config.js + </aio-file> + + + <aio-file> + tsconfig.json + </aio-file> + + + </aio-folder> + + + <aio-file> + node_modules ... + </aio-file> + + + <aio-file> + package.json + </aio-file> + + + </aio-folder> + + +</aio-filetree> + +Here are the code files we discussed in this chapter. + +<md-tab-group> + + <md-tab label="src/app/hero.service.ts"> + {@example 'toh-4/ts/src/app/hero.service.ts'} + </md-tab> + + + <md-tab label="src/app/app.component.ts"> + {@example 'toh-4/ts/src/app/app.component.ts'} + </md-tab> + + + <md-tab label="src/app/mock-heroes.ts"> + {@example 'toh-4/ts/src/app/mock-heroes.ts'} + </md-tab> + + +</md-tab-group> + +## The Road We’ve Travelled +Let’s take stock of what we’ve built. + +* We created a service class that can be shared by many components. +* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates. +* We defined our `HeroService` as a provider for our `AppComponent`. +* We created mock hero data and imported them into our service. +* We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}. + +Run the <live-example></live-example> for this part. + +### The Road Ahead +Our Tour of Heroes has become more reusable using shared components and services. +We want to create a dashboard, add menu links that route between the views, and format data in a template. +As our app evolves, we’ll learn how to design it to make it easier to grow and maintain. + +We learn about Angular Component Router and navigation among the views in the [next tutorial](toh-pt5.html) chapter. + +<a id="slow"></a>### Appendix: Take it slow + +We can simulate a slow connection. + +Import the `Hero` symbol and add the following `getHeroesSlowly` method to the `HeroService` + +{@example 'toh-4/ts/src/app/hero.service.ts' region='get-heroes-slowly'} + +Like `getHeroes`, it also returns a !{_Promise}. +But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes. + +Back in the `AppComponent`, replace `heroService.getHeroes` with `heroService.getHeroesSlowly` +and see how the app behaves. \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt5.md b/aio/content/tutorial/toh-pt5.md new file mode 100644 index 0000000000..aa3b2e50fc --- /dev/null +++ b/aio/content/tutorial/toh-pt5.md @@ -0,0 +1,510 @@ +@title +Routing + +@intro +We add the Angular Router and learn to navigate among the views + +@description +We received new requirements for our Tour of Heroes application: + +* Add a *Dashboard* view. +* Navigate between the *Heroes* and *Dashboard* views. +* Clicking on a hero in either view navigates to a detail view of the selected hero. +* Clicking a *deep link* in an email opens the detail view for a particular hero. + +When we’re done, users will be able to navigate the app like this: + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations"> </img> +</figure> + +We'll add Angular’s *Router* to our app to satisfy these requirements. + +The [Routing and Navigation](../guide/router.html) chapter covers the router +in more detail than we will in this tutorial. +Run the <live-example></live-example> for this part. + +## Where We Left Off + +Before we continue with our Tour of Heroes, let’s verify that +we have the following structure after adding our hero service +and hero detail component. If not, we’ll need to go back and follow the previous chapters. +The application runs and updates automatically as we continue to build the Tour of Heroes. + +## Action plan + +Here's our plan: + +* Turn `AppComponent` into an application shell that only handles navigation +* Relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent` +* Add routing +* Create a new `DashboardComponent` +* Tie the *Dashboard* into the navigation structure + +*Routing* is another name for *navigation*. The *router* is the mechanism for navigating from view to view. + +## Splitting the *AppComponent* + +Our current app loads `AppComponent` and immediately displays the list of heroes. + +Our revised app should present a shell with a choice of views (*Dashboard* and *Heroes*) +and then default to one of them. + +The `AppComponent` should only handle navigation. +Let's move the display of *Heroes* out of `AppComponent` and into its own `HeroesComponent`. + +### *HeroesComponent* + +`AppComponent` is already dedicated to *Heroes*. +Instead of moving anything out of `AppComponent`, we'll just rename it `HeroesComponent` +and create a new `AppComponent` shell separately. + +The steps are to rename: +* <span ngio-ex>app.component.ts</span> file to <span ngio-ex>heroes.component.ts</span> +* `AppComponent` class to `HeroesComponent` (rename locally, _only_ in this file) +* Selector `my-app` to `my-heroes` +## Create *AppComponent* + +The new `AppComponent` will be the application shell. +It will have some navigation links at the top and a display area below for the pages we navigate to. + +The initial steps are: + +* Create the file <span ngio-ex>src/app/app.component.ts</span>. +* Define an <span if-docs="ts">exported</span> `AppComponent` class. +* Add an `@Component` !{_decorator} above the class with a `my-app` selector. +* Move the following from `HeroesComponent` to `AppComponent`: + * `title` class property + * `@Component` template `<h1>` element, which contains a binding to `title` +* Add a `<my-heroes>` element to the app template just below the heading so we still see the heroes. +* Add `HeroesComponent` to the `!{_declsVsDirectives}` !{_array} of `!{_AppModuleVsAppComp}` so Angular recognizes the `<my-heroes>` tags. +* Add `HeroService` to the `providers` !{_array} of `!{_AppModuleVsAppComp}` because we'll need it in every other view. +* Remove `HeroService` from the `HeroesComponent` `providers` !{_array} since it has been promoted. +* Add the supporting `import` statements for `AppComponent`. + +Our first draft looks like this: +The app still runs and still displays heroes. +Our refactoring of `AppComponent` into a new `AppComponent` and a `HeroesComponent` worked! +We have done no harm. +## Add Routing + +We're ready to take the next step. +Instead of displaying heroes automatically, we'd like to show them *after* the user clicks a button. +In other words, we'd like to navigate to the list of heroes. + +We'll need the Angular *Router*. + + +{@a configure-routes} +*Routes* tell the router which views to display when a user clicks a link or +pastes a URL into the browser address bar. + +Let's define our first route as a route to the heroes component: +The `!{_RoutesVsAtRouteConfig}` !{_are} !{_an} !{_array} of *route definitions*. +We have only one route definition at the moment but rest assured, we'll add more. + +This *route definition* has the following parts: + +- **path**: the router matches this route's path to the URL in the browser address bar (`!{_routePathPrefix}heroes`). +<li if-docs="dart"> **name**: the official name of the route; + it *must* begin with a capital letter to avoid confusion with the *path* (`Heroes`).</li> +- **component**: the component that the router should create when navigating to this route (`HeroesComponent`). + +Learn more about defining routes with `!{_RoutesVsAtRouteConfig}` in the [Routing](../guide/router.html) chapter. +### Router Outlet + +If we paste the path, `/heroes`, into the browser address bar, +the router should match it to the `!{_heroesRoute}` route and display the `HeroesComponent`. +But where? + +We have to ***tell it where*** by adding a `<router-outlet>` element to the bottom of the template. +`RouterOutlet` is one of the <span if-docs="ts">directives provided by</span> the `!{_RouterModuleVsRouterDirectives}`. +The router displays each component immediately below the `<router-outlet>` as we navigate through the application. + +### Router Links + +We don't really expect users to paste a route URL into the address bar. +We add an anchor tag to the template which, when clicked, triggers navigation to the `HeroesComponent`. + +The revised template looks like this: +Refresh the browser. We see only the app title and heroes link. We don't see the heroes list. + +The browser's address bar shows `/`. +The route path to `HeroesComponent` is `/heroes`, not `/`. +We don't have a route that matches the path `/`, so there is nothing to show. +That's something we'll want to fix. +We click the *Heroes* navigation link, the browser bar updates to `/heroes`, +and now we see the list of heroes. We are navigating at last! + +At this stage, our `AppComponent` looks like this. + + +{@example 'toh-pt5/ts/src/app/app.component.1.ts' region='v2'} + +The *AppComponent* is now attached to a router and displaying routed views. +For this reason and to distinguish it from other kinds of components, +we call this type of component a *Router Component*. +## Add a *Dashboard* + +Routing only makes sense when we have multiple views. We need another view. + +Create a placeholder `DashboardComponent` that gives us something to navigate to and from. +We’ll come back and make it more useful later. + +### Configure the dashboard route + +Go back to `!{_appRoutingTsVsAppComp}` and teach it to navigate to the dashboard. + +Import the dashboard component and +add the following route definition to the `!{_RoutesVsAtRouteConfig}` !{_array} of definitions. +#### !{_redirectTo} + +We want the app to show the dashboard when it starts and +we want to see a nice URL in the browser address bar that says `/dashboard`. +Remember that the browser launches with `/` in the address bar. +#### Add navigation to the template + +Finally, add a dashboard navigation link to the template, just above the *Heroes* link. + +We nested the two links within `<nav>` tags. +They don't do anything yet but they'll be convenient when we style the links a little later in the chapter. +To see these changes in your browser, go to the application root (`/`) and reload. +The app displays the dashboard and we can navigate between the dashboard and the heroes. + +## Dashboard Top Heroes + +Let’s spice up the dashboard by displaying the top four heroes at a glance. + +Replace the `template` metadata with a `templateUrl` property that points to a new +template file.Create that file with this content: + + +{@example 'toh-pt5/ts/src/app/dashboard.component.1.html'} + +We use `*ngFor` once again to iterate over a list of heroes and display their names. +We added extra `<div>` elements to help with styling later in this chapter. + +### Share the *HeroService* + +We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}. + +Recall earlier in the chapter that we removed the `HeroService` from the `providers` !{_array} of `HeroesComponent` +and added it to the `providers` !{_array} of `!{_AppModuleVsAppComp}`. + +That move created a singleton `HeroService` instance, available to *all* components of the application. +Angular will inject `HeroService` and we'll use it here in the `DashboardComponent`. + +### Get heroes + +Open <span ngio-ex>dashboard.component.ts</span> and add the requisite `import` statements. +Now implement the `DashboardComponent` class like this: +We've seen this kind of logic before in the `HeroesComponent`: + +* Define a `heroes` !{_array} property. +* Inject the `HeroService` in the constructor and hold it in a private `!{_priv}heroService` field. +* Call the service to get heroes inside the Angular `ngOnInit` lifecycle hook. + +In this dashboard we cherry-pick four heroes (2nd, 3rd, 4th, and 5th)<span if-docs="ts"> with the `Array.slice` method</span>. + +Refresh the browser and see four heroes in the new dashboard. + +## Navigate to Hero Details + +Although we display the details of a selected hero at the bottom of the `HeroesComponent`, +we don't yet *navigate* to the `HeroDetailComponent` in the three ways specified in our requirements: + +1. from the *Dashboard* to a selected hero. +1. from the *Heroes* list to a selected hero. +1. from a "deep link" URL pasted into the browser address bar. + +Adding a hero-detail route seems like an obvious place to start. + +### Routing to a hero detail + +We'll add a route to the `HeroDetailComponent` in `!{_appRoutingTsVsAppComp}` where our other routes are configured. + +The new route is a bit unusual in that we must tell the `HeroDetailComponent` *which hero to show*. +We didn't have to tell the `HeroesComponent` or the `DashboardComponent` anything. + +At the moment the parent `HeroesComponent` sets the component's `hero` property to a +hero object with a binding like this. + +<code-example language="html"> + <my-hero-detail [hero]="selectedHero"></my-hero-detail> + +</code-example> + +That clearly won't work in any of our routing scenarios. +Certainly not the last one; we can't embed an entire hero object in the URL! Nor would we want to. + +### Parameterized route + +We *can* add the hero's `id` to the URL. When routing to the hero whose `id` is 11, +we could expect to see a URL such as this: + +<code-example format="nocode"> + /detail/11 + +</code-example> + +The `/detail/` part of that URL is constant. The trailing numeric `id` part changes from hero to hero. +We need to represent that variable part of the route with a *parameter* (or *token*) that stands for the hero's `id`. + +### Configure a Route with a Parameter + +Here's the *route definition* we'll use. +The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id` +when navigating to the `HeroDetailComponent`. +We're finished with the application routes. + +We won't add a `'Hero Detail'` link to the template because users +don't click a navigation *link* to view a particular hero. +They click a *hero* whether that hero is displayed on the dashboard or in the heroes list. + +We'll get to those *hero* clicks later in the chapter. +There's no point in working on them until the `HeroDetailComponent` +is ready to be navigated *to*. + +That will require an `HeroDetailComponent` overhaul. + +## Revise the *HeroDetailComponent* + +Before we rewrite the `HeroDetailComponent`, let's review what it looks like now: + + +{@example 'toh-4/ts/src/app/hero-detail.component.ts'} + +The template won't change. We'll display a hero the same way. +The big changes are driven by how we get the hero. +First, add the requisite imports: +Let's have the `!{_ActivatedRoute}` service, the `HeroService` and the `Location` service injected +into the constructor, saving their values in private fields: +We tell the class that we want to implement the `OnInit` interface. +The hero `id` is a number. Route parameters are *always strings*. +So we convert the route parameter value to a number with the !{_str2int}. +### Add *HeroService.getHero* + +The problem with this bit of code is that `HeroService` doesn't have a `getHero` method! +We better fix that quickly before someone notices that we broke the app. + +Open `HeroService` and add a `getHero` method that filters the heroes list from `getHeroes` by `id`: +Let's return to the `HeroDetailComponent` to clean up loose ends. + +### Find our way back + +We can navigate *to* the `HeroDetailComponent` in several ways. +How do we navigate somewhere else when we're done? + +The user could click one of the two links in the `AppComponent`. Or click the browser's back button. +We'll add a third option, a `goBack` method that navigates backward one step in the browser's history stack +using the `Location` service we injected previously. + +Going back too far could take us out of the application. +That's acceptable in a demo. We'd guard against it in a real application, +perhaps with the [!{_CanDeactivateGuard}](../api/!{_CanDeactivateGuardUri}.html). +Then we wire this method with an event binding to a *Back* button that we +add to the bottom of the component template. +Modifying the template to add this button spurs us to take one more +incremental improvement and migrate the template to its own file, +called <span ngio-ex>hero-detail.component.html</span>: + + +{@example 'toh-pt5/ts/src/app/hero-detail.component.html'} + +We update the component metadata with a <span if-docs="ts">`moduleId` and a </span>`templateUrl` pointing to the template file that we just created. +Refresh the browser and see the results. + +## Select a *Dashboard* Hero + +When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero. + +Although the dashboard heroes are presented as button-like blocks, they should behave like anchor tags. +When hovering over a hero block, the target URL should display in the browser status bar +and the user should be able to copy the link or open the hero detail view in a new tab. + +To achieve this effect, reopen the `dashboard.component.html` and replace the repeated `<div *ngFor...>` tags +with `<a>` tags. The opening `<a>` tag looks like this: + + +{@example 'toh-pt5/ts/src/app/dashboard.component.html' region='click'} + +Notice the `[routerLink]` binding. + +Top level navigation in the [`AppComponent` +template](#router-links) has router links set to fixed !{_pathVsName}s of the +destination routes, "/dashboard" and "/heroes". + +This time, we're binding to an expression containing a **link parameters !{_array}**. +The !{_array} has two elements, the ***!{_pathVsName}*** of +the destination route and a ***route parameter*** set to the value of the current hero's `id`. + +The two !{_array} items align with the ***!{_pathVsName}*** and ***:id*** +token in the parameterized hero detail route definition we added to +`!{_appRoutingTsVsAppComp}` earlier in the chapter: +Refresh the browser and select a hero from the dashboard; the app should navigate directly to that hero’s details. + +## Select a Hero in the *HeroesComponent* + +Earlier we added the ability to select a hero from the dashboard. +We'll do something similar in the `HeroesComponent`. + +The `HeroesComponent` template exhibits a "master/detail" style with the list of heroes +at the top and details of the selected hero below. + + +{@example 'toh-4/ts/src/app/app.component.ts' region='template'} + +Our goal is to move the detail to its own view and navigate to it when the user decides to edit a selected hero. + +Delete the `<h1>` at the top (we forgot about it during the `AppComponent`-to-`HeroesComponent` conversion). + +Delete the last line of the template with the `<my-hero-detail>` tags. + +We'll no longer show the full `HeroDetailComponent` here. +We're going to display the hero detail on its own page and route to it as we did in the dashboard. + +We'll throw in a small twist for variety. +We are keeping the "master/detail" style but shrinking the detail to a "mini", read-only version. +When the user selects a hero from the list, we *don't* go to the detail page. +We show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page. + +### Add the *mini-detail* + +Add the following HTML fragment at the bottom of the template where the `<my-hero-detail>` used to be: +After clicking a hero, the user should see something like this below the hero list: + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/mini-hero-detail.png' alt="Mini Hero Detail" height="70"> </img> +</figure> + +### Format with the *uppercase* pipe + +Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `uppercase` pipe +that we slipped into the interpolation binding. Look for it right after the pipe operator ( | ). +Pipes are a good way to format strings, currency amounts, dates and other display data. +Angular ships with several pipes and we can write our own. + +Learn about pipes in the [Pipes](../guide/pipes.html) chapter. +### Move content out of the component file + +We are not done. We still have to update the component class to support navigation to the +`HeroDetailComponent` when the user clicks the *View Details* button. + +This component file is really big. Most of it is either template or CSS styles. +It's difficult to find the component logic amidst the noise of HTML and CSS. + +Let's migrate the template and the styles to their own files before we make any more changes: + +1. *Cut-and-paste* the template contents into a new <span ngio-ex>heroes.component.html</span> file. +1. *Cut-and-paste* the styles contents into a new <span ngio-ex>heroes.component.css</span> file. +1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files. +<li if-docs="ts">. *Set* the `moduleId` property to `module.id` so that `templateUrl` and `styleUrls` are relative to the component.</li> + +The `styleUrls` property is !{_an} !{_array} of style file names (with paths). +We could list multiple style files from different locations if we needed them. +### Update the _HeroesComponent_ class. + +The `HeroesComponent` navigates to the `HeroDetailComponent` in response to a button click. +The button's _click_ event is bound to a `gotoDetail` method that navigates _imperatively_ +by telling the router where to go. + +This approach requires some changes to the component class: + +1. Import the `router` from the Angular router library +1. Inject the `router` in the constructor (along with the `HeroService`) +1. Implement `gotoDetail` by calling the `router.navigate` method +Note that we're passing a two-element **link parameters !{_array}** +— a path and the route parameter — to +the `router.navigate` method just as we did in the `[routerLink]` binding +back in the `DashboardComponent`. +Here's the fully revised `HeroesComponent` class: +Refresh the browser and start clicking. +We can navigate around the app, from the dashboard to hero details and back, +for heroes list to the mini-detail to the hero details and back to the heroes again. +We can jump back and forth between the dashboard and the heroes. + +We've met all of the navigational requirements that propelled this chapter. + +## Styling the App + +The app is functional but pretty ugly. +Our creative designer team provided some CSS files to make it look better. + +### A Dashboard with Style + +The designers think we should display the dashboard heroes in a row of rectangles. +They've given us ~60 lines of CSS for this purpose including some simple media queries for responsive design. + +If we paste these ~60 lines into the component `styles` metadata, +they'll completely obscure the component logic. +Let's not do that. It's easier to edit CSS in a separate `*.css` file anyway. + +Add a <span ngio-ex>dashboard.component.css</span> file to the `!{_appDir}` folder and reference +that file in the component metadata's `styleUrls` !{_array} property like this: +### Stylish Hero Details + +The designers also gave us CSS styles specifically for the `HeroDetailComponent`. + +Add a <span ngio-ex>hero-detail.component.css</span> to the `!{_appDir}` +folder and refer to that file inside +the `styleUrls` !{_array} as we did for `DashboardComponent`. +Let's also remove the `hero` property `@Input` !{_decorator} +<span if-docs="ts">and its import</span> +while we are at it. + +Here's the content for the aforementioned component CSS files. +### Style the Navigation Links + +The designers gave us CSS to make the navigation links in our `AppComponent` look more like selectable buttons. +We cooperated by surrounding those links in `<nav>` tags. + +Add a <span ngio-ex>app.component.css</span> file to the `!{_appDir}` folder with the following content. + +### Global application styles + +When we add styles to a component, we're keeping everything a component needs +— HTML, the CSS, the code — together in one convenient place. +It's pretty easy to package it all up and re-use the component somewhere else. + +We can also create styles at the *application level* outside of any component. + +Our designers provided some basic styles to apply to elements across the entire app. +These correspond to the full set of master styles that we installed earlier during [setup](../guide/setup.html). +Here is an excerpt: +Create the file <span ngio-ex>styles.css</span>, if it doesn't exist already. +Ensure that it contains the [master styles given here](!{styles_css}). + +If necessary, also edit <span ngio-ex>index.html</span> to refer to this stylesheet. +Look at the app now. Our dashboard, heroes, and navigation links are styling! + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/dashboard-top-heroes.png' alt="View navigations"> </img> +</figure> + + +## Application structure and code + +Review the sample source code in the <live-example></live-example> for this chapter. +Verify that we have the following structure: + +## Recap + +### The Road Behind + +We travelled a great distance in this chapter + +- We added the Angular *Router* to navigate among different components. +- We learned how to create router links to represent navigation menu items. +- We used router link parameters to navigate to the details of user selected hero. +- We shared the `HeroService` among multiple components. +- We moved HTML and CSS out of the component file and into their own files. +- We added the `uppercase` pipe to format data. +<li if-docs="ts"> We refactored routes into a `Routing Module` that we import.</li> + +### The Road Ahead + +We have much of the foundation we need to build an application. +We're still missing a key piece: remote data access. + +In the next chapter, +we’ll replace our mock data with data retrieved from a server using http. \ No newline at end of file diff --git a/aio/content/tutorial/toh-pt6.md b/aio/content/tutorial/toh-pt6.md new file mode 100644 index 0000000000..bc175e7480 --- /dev/null +++ b/aio/content/tutorial/toh-pt6.md @@ -0,0 +1,293 @@ +@title +HTTP + +@intro +We convert our service and components to use Angular's HTTP service + +@description +Our stakeholders appreciate our progress. +Now they want to get the hero data from a server, let users add, edit, and delete heroes, +and save these changes back to the server. + +In this chapter we teach our application to make the corresponding HTTP calls to a remote server's web API. + +Run the <live-example></live-example> for this part. + +## Where We Left Off + +In the [previous chapter](toh-pt5.html), we learned to navigate between the dashboard and the fixed heroes list, editing a selected hero along the way. +That's our starting point for this chapter. +The application runs and updates automatically as we continue to build the Tour of Heroes. + + +<h1> + Providing HTTP Services +</h1> + +### Register for HTTP services + +## Simulating the web API + +We recommend registering application-wide services in the root +`!{_AppModuleVsAppComp}` *providers*. <span if-docs="dart">Here we're +registering in `main` for a special reason.</span> + +Our application is in the early stages of development and far from ready for production. +We don't even have a web server that can handle requests for heroes. +Until we do, *we'll have to fake it*. + +We're going to *trick* the HTTP client into fetching and saving data from +a mock service, the *in-memory web API*. +<span if-docs="dart"> The application itself doesn't need to know and +shouldn't know about this. So we'll slip the in-memory web API into the +configuration *above* the `AppComponent`.</span> + +Here is a version of <span ngio-ex>!{_appModuleTsVsMainTs}</span> that performs this trick: + + +{@example 'toh-pt6/ts/src/app/in-memory-data.service.ts' region='init'} + + +<p> + This file replaces the <code> </code> which is now safe to delete. +</p> + + +## Heroes and HTTP + +Look at our current `HeroService` implementation +We returned a !{_Promise} resolved with mock heroes. +It may have seemed like overkill at the time, but we were anticipating the +day when we fetched heroes with an HTTP client and we knew that would have to be an asynchronous operation. + +That day has arrived! Let's convert `getHeroes()` to use HTTP. +Our updated import statements are now: +Refresh the browser, and the hero data should be successfully loaded from the +mock server. + +<h3 id="!{_h3id}">HTTP !{_Promise}</h3> + +We're still returning a !{_Promise} but we're creating it differently. +That response JSON has a single `data` property. +The `data` property holds the !{_array} of *heroes* that the caller really wants. +So we grab that !{_array} and return it as the resolved !{_Promise} value. + + +~~~ {.alert.is-important} + +Pay close attention to the shape of the data returned by the server. +This particular *in-memory web API* example happens to return an object with a `data` property. +Your API might return something else. Adjust the code to match *your web API*. + + +~~~ + +The caller is unaware of these machinations. It receives a !{_Promise} of *heroes* just as it did before. +It has no idea that we fetched the heroes from the (mock) server. +It knows nothing of the twists and turns required to convert the HTTP response into heroes. +Such is the beauty and purpose of delegating data access to a service like this `HeroService`. + +### Error Handling + +At the end of `getHeroes()` we `catch` server failures and pass them to an error handler: +This is a critical step! +We must anticipate HTTP failures as they happen frequently for reasons beyond our control. +In this demo service we log the error to the console; we would do better in real life. + +We've also decided to return a user friendly form of the error to +the caller in a !{rejected_promise} so that the caller can display a proper error message to the user. + +### Get hero by id +The `HeroDetailComponent` asks the `HeroService` to fetch a single hero to edit. + +The `HeroService` currently fetches all heroes and then finds the desired hero +by filtering for the one with the matching `id`. +That's fine in a simulation. It's wasteful to ask a real server for _all_ heroes when we only want one. +Most web APIs support a _get-by-id_ request in the form `api/hero/:id` (e.g., `api/hero/11`). + +Update the `HeroService.getHero` method to make a _get-by-id_ request, +applying what we just learned to write `getHeroes`:It's almost the same as `getHeroes`. +The URL identifies _which_ hero the server should update by encoding the hero id into the URL +to match the `api/hero/:id` pattern. + +We also adjust to the fact that the `data` in the response is a single hero object rather than !{_an} !{_array}. + +### Unchanged _getHeroes_ API + +Although we made significant *internal* changes to `getHeroes()` and `getHero()`, +the public signatures did not change. +We still return a !{_Promise} from both methods. +We won't have to update any of the components that call them. + +Our stakeholders are thrilled with the web API integration so far. +Now they want the ability to create and delete heroes. + +Let's see first what happens when we try to update a hero's details. + +## Update hero details + +We can edit a hero's name already in the hero detail view. Go ahead and try +it. As we type, the hero name is updated in the view heading. +But when we hit the `Back` button, the changes are lost! + +Updates weren't lost before. What changed? +When the app used a list of mock heroes, updates were applied directly to the +hero objects within the single, app-wide, shared list. Now that we are fetching data +from a server, if we want changes to persist, we'll need to write them back to +the server. + +### Save hero details + +Let's ensure that edits to a hero's name aren't lost. Start by adding, +to the end of the hero detail template, a save button with a `click` event +binding that invokes a new component method named `save`: +The `save` method persists hero name changes using the hero service +`update` method and then navigates back to the previous view: +### Hero service `update` method + +The overall structure of the `update` method is similar to that of +`getHeroes`, although we'll use an HTTP _put_ to persist changes +server-side: +We identify _which_ hero the server should update by encoding the hero id in +the URL. The put body is the JSON string encoding of the hero, obtained by +calling `!{_JSON_stringify}`. We identify the body content type +(`application/json`) in the request header. + +Refresh the browser and give it a try. Changes to hero names should now persist. + +## Add a hero + +To add a new hero we need to know the hero's name. Let's use an input +element for that, paired with an add button. + +Insert the following into the heroes component HTML, first thing after +the heading: +In response to a click event, we call the component's click handler and then +clear the input field so that it will be ready to use for another name. +When the given name is non-blank, the handler delegates creation of the +named hero to the hero service, and then adds the new hero to our !{_array}. + +Finally, we implement the `create` method in the `HeroService` class.Refresh the browser and create some new heroes! + +## Delete a hero + +Too many heroes? +Let's add a delete button to each hero in the heroes view. + +Add this button element to the heroes component HTML, right after the hero +name in the repeated `<li>` tag: +The `<li>` element should now look like this: +In addition to calling the component's `delete` method, the delete button +click handling code stops the propagation of the click event — we +don't want the `<li>` click handler to be triggered because that would +select the hero that we are going to delete! + +The logic of the `delete` handler is a bit trickier: +Of course, we delegate hero deletion to the hero service, but the component +is still responsible for updating the display: it removes the deleted hero +from the !{_array} and resets the selected hero if necessary. +We want our delete button to be placed at the far right of the hero entry. +This extra CSS accomplishes that: +### Hero service `delete` method + +The hero service's `delete` method uses the _delete_ HTTP method to remove the hero from the server: +Refresh the browser and try the new delete functionality. + +<div id='observables'> + +</div> + +## !{_Observable}s +But requests aren't always "one and done". We may start one request, +then cancel it, and make a different request before the server has responded to the first request. +Such a _request-cancel-new-request_ sequence is difficult to implement with *!{_Promise}s*. +It's easy with *!{_Observable}s* as we'll see. + +### Search-by-name + +We're going to add a *hero search* feature to the Tour of Heroes. +As the user types a name into a search box, we'll make repeated HTTP requests for heroes filtered by that name. + +We start by creating `HeroSearchService` that sends search queries to our server's web api. + + +{@example 'toh-pt6/ts/src/app/hero-search.service.ts'} + +The `!{_priv}http.get()` call in `HeroSearchService` is similar to the one +in the `HeroService`, although the URL now has a query string. +### HeroSearchComponent + +Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`. + +The component template is simple — just a text box and a list of matching search results. + + +{@example 'toh-pt6/ts/src/app/hero-search.component.html'} + +We'll also want to add styles for the new component. + +{@example 'toh-pt6/ts/src/app/hero-search.component.css'} + +As the user types in the search box, a *keyup* event binding calls the component's `search` method with the new search box value. + +The `*ngFor` repeats *hero* objects from the component's `heroes` property. No surprise there. + +But, as we'll soon see, the `heroes` property is now !{_an} *!{_Observable}* of hero !{_array}s, rather than just a hero !{_array}. +The `*ngFor` can't do anything with !{_an} `!{_Observable}` until we flow it through the `async` pipe (`AsyncPipe`). +The `async` pipe subscribes to the `!{_Observable}` and produces the !{_array} of heroes to `*ngFor`. + +Time to create the `HeroSearchComponent` class and metadata. + + +{@example 'toh-pt6/ts/src/app/hero-search.component.ts'} + +#### Search terms + +Let's focus on the `!{_priv}searchTerms`: +<a id="ngoninit"></a> +#### Initialize the _**heroes**_ property (_**ngOnInit**_) + +<span if-docs="ts">A `Subject` is also an `Observable`.</span> +We're going to turn the stream +of search terms into a stream of `Hero` !{_array}s and assign the result to the `heroes` property. +If we passed every user keystroke directly to the `HeroSearchService`, we'd unleash a storm of HTTP requests. +Bad idea. We don't want to tax our server resources and burn through our cellular network data plan. +### Add the search component to the dashboard + +We add the hero search HTML element to the bottom of the `DashboardComponent` template. + + +{@example 'toh-pt6/ts/src/app/dashboard.component.html'} + +Finally, we import `HeroSearchComponent` from +<span ngio-ex>hero-search.component.ts</span> +and add it to the `!{_declarations}` !{_array}: +Run the app again, go to the *Dashboard*, and enter some text in the search box. +At some point it might look like this. + +<figure class='image-display'> + <img src='/resources/images/devguide/toh/toh-hero-search.png' alt="Hero Search Component"> </img> +</figure> + + +## Application structure and code + +Review the sample source code in the <live-example></live-example> for this chapter. +Verify that we have the following structure: + +## Home Stretch + +We are at the end of our journey for now, but we have accomplished a lot. +- We added the necessary dependencies to use HTTP in our application. +- We refactored `HeroService` to load heroes from a web API. +- We extended `HeroService` to support post, put and delete methods. +- We updated our components to allow adding, editing and deleting of heroes. +- We configured an in-memory web API. +- We learned how to use !{_Observable}s. + +Here are the files we _added or changed_ in this chapter. + +### Next Step + +Return to the [learning path](../guide/learning-angular.html#architecture) where +you can read about the concepts and practices you discovered in this tutorial. \ No newline at end of file