chore(jade): upgrade to use marked filter

The `Transformers.markdown` (`:markdown`) filter is deprecated. This commit updates
the entire docs project to use the `jstransformer-marked` (`:marked') filter.
This commit is contained in:
Peter Bacon Darwin 2015-11-10 18:31:46 +00:00
parent 0f61ea288f
commit e86fde8dc9
31 changed files with 1866 additions and 1865 deletions

View File

@ -60,5 +60,8 @@
"q": "^1.4.1", "q": "^1.4.1",
"typescript": "~1.5.3", "typescript": "~1.5.3",
"yargs": "^3.23.0" "yargs": "^3.23.0"
},
"dependencies": {
"jstransformer-marked": "^1.0.1"
} }
} }

View File

@ -11,7 +11,7 @@ include ../../../_includes/_util-fns
.showcase-content .showcase-content
.l-sub-section .l-sub-section
:markdown :marked
### Including a code example from the `_examples` folder ### Including a code example from the `_examples` folder
One of the design goals for this documention was that any code samples that appear within the documentation be 'testable'. One of the design goals for this documention was that any code samples that appear within the documentation be 'testable'.
@ -35,7 +35,7 @@ include ../../../_includes/_util-fns
code-example(language="js"). code-example(language="js").
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
The syntax for the `makeExample` mixin is: The syntax for the `makeExample` mixin is:
#### +makeExample(filePath, region, title, stylePattern) #### +makeExample(filePath, region, title, stylePattern)
@ -49,14 +49,14 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
+makeExample('styleguide/js/index.html', null, 'index.html') +makeExample('styleguide/js/index.html', null, 'index.html')
:markdown :marked
This will read the *_examples/styleguide/js/index.html* file and include it This will read the *_examples/styleguide/js/index.html* file and include it
with the heading 'index.html'. Note that the file will be properly escaped and with the heading 'index.html'. Note that the file will be properly escaped and
color coded according to the extension on the file ( html in this case). color coded according to the extension on the file ( html in this case).
+makeExample('styleguide/js/index.html', null, 'index.html') +makeExample('styleguide/js/index.html', null, 'index.html')
:markdown :marked
The second parameter with a value of 'null' will be described later in this document. The second parameter with a value of 'null' will be described later in this document.
There is a similar `makeTabs` mixin that provides the same service but for multiple examples There is a similar `makeTabs` mixin that provides the same service but for multiple examples
@ -73,13 +73,13 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test') +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test')
:markdown :marked
This will create two tabs, each with its own title and appropriately color coded. This will create two tabs, each with its own title and appropriately color coded.
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test') +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test')
.l-sub-section .l-sub-section
:markdown :marked
### Marking up an example file for use by the `makeExample` and `makeTabs` mixins ### Marking up an example file for use by the `makeExample` and `makeTabs` mixins
At a minimum, marking up an example file simply consists of adding a single comment line to the top of the file At a minimum, marking up an example file simply consists of adding a single comment line to the top of the file
@ -98,7 +98,7 @@ include ../../../_includes/_util-fns
}); });
}); });
:markdown :marked
If a file only has a single `#docregion` then the entire file AFTER the `#docregion` comment is available for inclusion If a file only has a single `#docregion` then the entire file AFTER the `#docregion` comment is available for inclusion
via mixin. Portions of the file can be indicated by surrounding an area of the file with via mixin. Portions of the file can be indicated by surrounding an area of the file with
`#docregion` and an `#enddocregion` tags. These regions, each with its own name, may be nested to any level and any regions that are not 'ended' explicitly `#docregion` and an `#enddocregion` tags. These regions, each with its own name, may be nested to any level and any regions that are not 'ended' explicitly
@ -130,7 +130,7 @@ include ../../../_includes/_util-fns
// #enddocregion // #enddocregion
// #enddocregion // #enddocregion
:markdown :marked
Multiple `#docregion` tags may be defined on a single line as shown below. In addition, anytime a file contains multiple Multiple `#docregion` tags may be defined on a single line as shown below. In addition, anytime a file contains multiple
`#docregion` tags with the same name they will automatically be combined. Each of the individually tagged sections of the combined document `#docregion` tags with the same name they will automatically be combined. Each of the individually tagged sections of the combined document
will be separated from one another by a comment consisting of '. . .'. This default separator, known will be separated from one another by a comment consisting of '. . .'. This default separator, known
@ -158,7 +158,7 @@ include ../../../_includes/_util-fns
doSomethingInteresting(); doSomethingInteresting();
// #enddocregion // #enddocregion
:markdown :marked
HTML files can also contain #docregion comments: HTML files can also contain #docregion comments:
code-example(format="linenums" language="html" escape="html"). code-example(format="linenums" language="html" escape="html").
@ -168,7 +168,7 @@ include ../../../_includes/_util-fns
<script src="app.js"></script> <script src="app.js"></script>
... ...
:markdown :marked
as can CSS files: as can CSS files:
code-example(format="linenums" language="css"). code-example(format="linenums" language="css").
@ -179,7 +179,7 @@ include ../../../_includes/_util-fns
} }
.l-sub-section .l-sub-section
:markdown :marked
### Including a named #docregion via the makeExample or makeTabs mixins. ### Including a named #docregion via the makeExample or makeTabs mixins.
In order to include just a portion of an example file that has been marked up with a 'named' `#docregion` In order to include just a portion of an example file that has been marked up with a 'named' `#docregion`
@ -189,14 +189,14 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
+makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region") +makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region")
:markdown :marked
is a request to include just the `class-w-annotations` region from the `app.js` file in the `_examples/styleguide` is a request to include just the `class-w-annotations` region from the `app.js` file in the `_examples/styleguide`
folder and results in the following: folder and results in the following:
+makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region") +makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region")
.l-sub-section .l-sub-section
:markdown :marked
### Additional styling ### Additional styling
In some cases you may want to add additional styling to an external file after it had been included in the documentation. In some cases you may want to add additional styling to an external file after it had been included in the documentation.
@ -215,7 +215,7 @@ include ../../../_includes/_util-fns
code-example(format="linenums" language="js" escape="none"). code-example(format="linenums" language="js" escape="none").
+makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*&ampquot;)/g}) +makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*&ampquot;)/g})
:markdown :marked
Which will mark all of the quoted contents of each `script` tag within the index.html file in pink. Which will mark all of the quoted contents of each `script` tag within the index.html file in pink.
.alert.is-important. .alert.is-important.
@ -224,20 +224,20 @@ include ../../../_includes/_util-fns
+makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*&quot;)/g}) +makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*&quot;)/g})
:markdown :marked
A more complicated example might be: A more complicated example might be:
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
- var stylePattern = { pnk: /script (src=.*&ampquot;)/g, otl: /(\S*my-app.*$)/m }; - var stylePattern = { pnk: /script (src=.*&ampquot;)/g, otl: /(\S*my-app.*$)/m };
+makeExample('styleguide/js/index.html', null, 'index.html', stylePattern ) +makeExample('styleguide/js/index.html', null, 'index.html', stylePattern )
:markdown :marked
Which applies multiple styles and uses an intermediate javascript object as opposed to a literal. Which applies multiple styles and uses an intermediate javascript object as opposed to a literal.
- var stylePattern = { pnk: /script (src=.*&quot;)/g, otl: /(\S*my-app.*$)/m }; - var stylePattern = { pnk: /script (src=.*&quot;)/g, otl: /(\S*my-app.*$)/m };
+makeExample('styleguide/js/index.html', null, 'index.html', stylePattern ) +makeExample('styleguide/js/index.html', null, 'index.html', stylePattern )
:markdown :marked
`makeTabs` support for `stylePatterns` is slightly different from the `makeExample` mixin in that you can also `makeTabs` support for `stylePatterns` is slightly different from the `makeExample` mixin in that you can also
pass in an array of stylePattern objects where each is paired with its corresponding 'tab'. If only a single stylePattern pass in an array of stylePattern objects where each is paired with its corresponding 'tab'. If only a single stylePattern
object is passed in then it is assumed to apply to all of the tabs. object is passed in then it is assumed to apply to all of the tabs.
@ -250,7 +250,7 @@ include ../../../_includes/_util-fns
+makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns) +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns)
.l-sub-section .l-sub-section
:markdown :marked
### Including a JSON file or just parts of one ### Including a JSON file or just parts of one
To include an '.json' file from somewhere in the `doc\_examples` folder you can use the `makeJson` mixin. The `makeExample` To include an '.json' file from somewhere in the `doc\_examples` folder you can use the `makeJson` mixin. The `makeExample`
@ -277,7 +277,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', null, "Entire package.json file") +makeJson('styleguide/package.json', null, "Entire package.json file")
:markdown :marked
A subset of the '.json' file can also be selected. A subset of the '.json' file can also be selected.
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
@ -285,7 +285,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', { paths: 'version, scripts.tsc, scripts.start '}, "Selected parts of the package.json file" ) +makeJson('styleguide/package.json', { paths: 'version, scripts.tsc, scripts.start '}, "Selected parts of the package.json file" )
:markdown :marked
Styling selected portions of the json is also supported. Styling selected portions of the json is also supported.
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
@ -293,7 +293,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*traceur.*)/, /(\Sangular2.*)/, /(\Ssystem.*)/ ]}) +makeJson('styleguide/package.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*traceur.*)/, /(\Sangular2.*)/, /(\Ssystem.*)/ ]})
:markdown :marked
As well as styling across multiple lines. As well as styling across multiple lines.
code-example(format="linenums" language="js"). code-example(format="linenums" language="js").
@ -304,7 +304,7 @@ include ../../../_includes/_util-fns
+makeJson('styleguide/package.json', {paths: 'name, version, dependencies '}, "Foo", styles ) +makeJson('styleguide/package.json', {paths: 'name, version, dependencies '}, "Foo", styles )
.l-sub-section .l-sub-section
:markdown :marked
### Inline code and code examples provided directly i.e. not from an example file. ### Inline code and code examples provided directly i.e. not from an example file.
The `makeExample` and `makeTabs` mixins are both both built on top of a custom jade 'style'; `code-example`. The `makeExample` and `makeTabs` mixins are both both built on top of a custom jade 'style'; `code-example`.
@ -391,7 +391,7 @@ include ../../../_includes/_util-fns
// TAB 2 CONTENT // TAB 2 CONTENT
.l-sub-section .l-sub-section
:markdown :marked
### Combining makeExample, makeTabs mixins with code-example style attributes ### Combining makeExample, makeTabs mixins with code-example style attributes
As mentioned above the `makeExample` and `makeTabs` mixins are built on top of the `code-example` style. By default As mentioned above the `makeExample` and `makeTabs` mixins are built on top of the `code-example` style. By default
the mixins automatically determine a language based on the example file's extensions and always include line numbers. the mixins automatically determine a language based on the example file's extensions and always include line numbers.
@ -403,12 +403,12 @@ include ../../../_includes/_util-fns
code-example(). code-example().
+makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15") +makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15")
:markdown :marked
Starts the numbering of the example at line 15. Starts the numbering of the example at line 15.
+makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15") +makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15")
:markdown :marked
Or to suppress line numbering completely you can use Or to suppress line numbering completely you can use
code-example(). code-example().
@ -417,7 +417,7 @@ include ../../../_includes/_util-fns
+makeExample('styleguide/js/app.js', 'class-w-annotations')(format=".") +makeExample('styleguide/js/app.js', 'class-w-annotations')(format=".")
.l-sub-section .l-sub-section
:markdown :marked
### Code examples in angular/angular source code ### Code examples in angular/angular source code
References to embedded example code in the angular/angular source make use of the same mixins as defined above, but with a slightly different References to embedded example code in the angular/angular source make use of the same mixins as defined above, but with a slightly different
@ -431,7 +431,7 @@ include ../../../_includes/_util-fns
Example files referenced by inline tags are all assumed to be in the 'modules/angular2' folder in the angular/angular repo. Example files referenced by inline tags are all assumed to be in the 'modules/angular2' folder in the angular/angular repo.
:markdown :marked
#### @example inline tag parameters #### @example inline tag parameters
- *filePath:* path to the example file under the '_examples' folder - *filePath:* path to the example file under the '_examples' folder
- *region:* (optional or null) region from the example file to display - *region:* (optional or null) region from the example file to display
@ -452,7 +452,7 @@ include ../../../_includes/_util-fns
* {@example core/directives/ng_if_spec.ts foo title='Foo' } * {@example core/directives/ng_if_spec.ts foo title='Foo' }
**/ **/
:markdown :marked
#### @exampleTabs inline tag parameters #### @exampleTabs inline tag parameters
- *filePaths:* a comma delimited string of filePaths to example files under the '_examples' folder - *filePaths:* a comma delimited string of filePaths to example files under the '_examples' folder
- *regions:* (optional or null) region from the example file to display - *regions:* (optional or null) region from the example file to display
@ -469,7 +469,7 @@ include ../../../_includes/_util-fns
**/ **/
.l-sub-section .l-sub-section
:markdown :marked
### Cross references to Developer guide pages in angular/angular source comments. ### Cross references to Developer guide pages in angular/angular source comments.
The '{@linkDevGuide ... }' inline tag is intended to be used to create links from api documentation to dev guide The '{@linkDevGuide ... }' inline tag is intended to be used to create links from api documentation to dev guide

View File

@ -1,11 +1,11 @@
include ../../../_includes/_util-fns include ../../../_includes/_util-fns
:markdown :marked
Let's start from zero and build a super simple Angular 2 application in Dart. Let's start from zero and build a super simple Angular 2 application in Dart.
.callout.is-helpful .callout.is-helpful
header Don't want Dart? header Don't want Dart?
:markdown :marked
Although we're getting started in Dart, you can also write Angular 2 apps Although we're getting started in Dart, you can also write Angular 2 apps
in TypeScript and JavaScript. in TypeScript and JavaScript.
Just select either of those languages from the combo-box in the banner. Just select either of those languages from the combo-box in the banner.
@ -27,7 +27,7 @@ p.
.l-main-section .l-main-section
h2#section-install-angular Set up a new app directory h2#section-install-angular Set up a new app directory
:markdown :marked
Create a new directory, Create a new directory,
and put a file named `pubspec.yaml` in it. and put a file named `pubspec.yaml` in it.
@ -73,7 +73,7 @@ p.
+makeExample('quickstart/dart/ex1/web/main.dart', null, 'web/main.dart') +makeExample('quickstart/dart/ex1/web/main.dart', null, 'web/main.dart')
:markdown :marked
You've just defined an Angular 2 **component**, You've just defined an Angular 2 **component**,
one of the most important Angular 2 features. one of the most important Angular 2 features.
Components are the primary way to create application views Components are the primary way to create application views
@ -121,7 +121,7 @@ p.
+makeExample('quickstart/dart/ex1/web/index.html', null, 'web/index.html') +makeExample('quickstart/dart/ex1/web/index.html', null, 'web/index.html')
:markdown :marked
The `<my-app>` tag in the `<body>` is The `<my-app>` tag in the `<body>` is
the custom HTML element defined in the Dart file. the custom HTML element defined in the Dart file.
@ -149,7 +149,7 @@ p.
Once the app is running, Once the app is running,
you should see <b>My First Angular 2 App</b> in your browser window. you should see <b>My First Angular 2 App</b> in your browser window.
:markdown :marked
If you don't see that, make sure you've entered all the code correctly If you don't see that, make sure you've entered all the code correctly
and run `pub get`. and run `pub get`.
@ -158,14 +158,14 @@ p.
h2#section-angular-run-app Generate JavaScript h2#section-angular-run-app Generate JavaScript
:markdown :marked
Before you can deploy your app, you need to generate JavaScript files. Before you can deploy your app, you need to generate JavaScript files.
Pub build makes that easy. Pub build makes that easy.
To improve your app's performance, convert the To improve your app's performance, convert the
HTML file to directly include the generated JavaScript; HTML file to directly include the generated JavaScript;
one way to do that is with dart_to_js_script_rewriter. one way to do that is with dart_to_js_script_rewriter.
:markdown :marked
Add the dart_to_js_script_rewriter package to your pubspec, Add the dart_to_js_script_rewriter package to your pubspec,
in both the `dependencies` and `transformers` sections. in both the `dependencies` and `transformers` sections.

View File

@ -1,15 +1,15 @@
include ../../../_includes/_util-fns include ../../../_includes/_util-fns
:markdown :marked
Let's start from zero and build a simple Angular 2 application in JavaScript. Let's start from zero and build a simple Angular 2 application in JavaScript.
.callout.is-helpful .callout.is-helpful
header Don't want JavaScript? header Don't want JavaScript?
:markdown :marked
Although we're getting started in JavaScript, you can also write Angular 2 apps Although we're getting started in JavaScript, you can also write Angular 2 apps
in TypeScript and Dart by selecting either of those languages from the combo-box in the banner. in TypeScript and Dart by selecting either of those languages from the combo-box in the banner.
:markdown :marked
We'll do it in six short steps We'll do it in six short steps
1. Create a project folder 1. Create a project folder
1. Install essential libraries 1. Install essential libraries
@ -19,7 +19,7 @@ include ../../../_includes/_util-fns
1. Run it 1. Run it
.l-main-section .l-main-section
:markdown :marked
## Create a project folder ## Create a project folder
**Create a new folder** to hold our application project, perhaps like this: **Create a new folder** to hold our application project, perhaps like this:
@ -28,7 +28,7 @@ include ../../../_includes/_util-fns
cd angular2-quickstart cd angular2-quickstart
``` ```
.l-main-section .l-main-section
:markdown :marked
## Install essential libraries ## Install essential libraries
We'll use the **npm package manager** to install packages for We'll use the **npm package manager** to install packages for
@ -44,11 +44,11 @@ include ../../../_includes/_util-fns
easy once we have it installed. easy once we have it installed.
.alert.is-helpful .alert.is-helpful
:markdown :marked
Don't have npm? [Get it now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm") Don't have npm? [Get it now](https://docs.npmjs.com/getting-started/installing-node "Installing Node.js and updating npm")
because we're going to use it now and repeatedly throughout this documentation. because we're going to use it now and repeatedly throughout this documentation.
:markdown :marked
**Open** a terminal window and enter these commands: **Open** a terminal window and enter these commands:
``` ```
npm init -y npm init -y
@ -61,23 +61,23 @@ include ../../../_includes/_util-fns
+makeJson('quickstart/js/package.json', { paths: 'name, version, dependencies, devDependencies'}) +makeJson('quickstart/js/package.json', { paths: 'name, version, dependencies, devDependencies'})
:markdown :marked
There is also a `scripts` section. **Find and replace** it with the following: There is also a `scripts` section. **Find and replace** it with the following:
+makeJson('quickstart/js/package.json', { paths: 'scripts'}) +makeJson('quickstart/js/package.json', { paths: 'scripts'})
:markdown :marked
We've just extended our project world with a script command that we'll be running very soon. We've just extended our project world with a script command that we'll be running very soon.
.l-main-section .l-main-section
:markdown :marked
## Our first Angular component ## Our first Angular component
Add a new file called *app.js* and paste the following lines: Add a new file called *app.js* and paste the following lines:
+makeExample('quickstart/js/app.js', 'class-w-annotations') +makeExample('quickstart/js/app.js', 'class-w-annotations')
:markdown :marked
We're creating a visual component named **`AppComponent`** by chaining the We're creating a visual component named **`AppComponent`** by chaining the
`Component` and `Class` methods that belong to the **global Angular namespace, `ng`**. `Component` and `Class` methods that belong to the **global Angular namespace, `ng`**.
@ -107,14 +107,14 @@ include ../../../_includes/_util-fns
We'll see more interesting component classes in future examples. We'll see more interesting component classes in future examples.
.l-main-section .l-main-section
:markdown :marked
## Bootstrap the app ## Bootstrap the app
We need to do something to put our application in motion. We need to do something to put our application in motion.
Add the following to the bottom of the `app.js` file: Add the following to the bottom of the `app.js` file:
+makeExample('quickstart/js/app.js', 'bootstrap') +makeExample('quickstart/js/app.js', 'bootstrap')
:markdown :marked
We'll wait for the browser to tell us that it has finished loading We'll wait for the browser to tell us that it has finished loading
all content and then we'll call the Angular `bootstrap` method. all content and then we'll call the Angular `bootstrap` method.
@ -134,14 +134,14 @@ include ../../../_includes/_util-fns
+makeExample('quickstart/js/app.js', 'dsl') +makeExample('quickstart/js/app.js', 'dsl')
.l-main-section .l-main-section
:markdown :marked
## Create an *index.html* ## Create an *index.html*
**Add a new `index.html`** file to the project folder and enter the following HTML **Add a new `index.html`** file to the project folder and enter the following HTML
+makeExample('quickstart/js/index.html', null, 'index.html')(format="") +makeExample('quickstart/js/index.html', null, 'index.html')(format="")
.l-sub-section .l-sub-section
:markdown :marked
Our app loads two script files in the `<head>` element: Our app loads two script files in the `<head>` element:
>***angular2.sfx.dev.js***, the Angular 2 development library that puts >***angular2.sfx.dev.js***, the Angular 2 development library that puts
@ -154,7 +154,7 @@ include ../../../_includes/_util-fns
application. Angular displays our application here. application. Angular displays our application here.
.l-main-section .l-main-section
:markdown :marked
## Run it! ## Run it!
We need a file server to serve the static assets of our application We need a file server to serve the static assets of our application
@ -170,10 +170,10 @@ include ../../../_includes/_util-fns
code npm start code npm start
.alert.is-helpful .alert.is-helpful
:markdown :marked
That's the `npm` command we added earlier to the `scripts` section of `package.json` That's the `npm` command we added earlier to the `scripts` section of `package.json`
:markdown :marked
**live-server** loads the browser for us and refreshes the page as we make **live-server** loads the browser for us and refreshes the page as we make
changes to the application. changes to the application.
@ -182,7 +182,7 @@ include ../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app") img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
:markdown :marked
### Make some changes ### Make some changes
The `live-server` detects changes to our files and refreshes the browser page for us automatically. The `live-server` detects changes to our files and refreshes the browser page for us automatically.

View File

@ -1,5 +1,5 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
Dependency Injection is an important application design pattern. Dependency Injection is an important application design pattern.
Angular has its own Dependency Injection framework and Angular has its own Dependency Injection framework and
we really can't build an Angular application without it. we really can't build an Angular application without it.
@ -7,7 +7,7 @@ include ../../../../_includes/_util-fns
In this chapter we'll learn what Dependency Injection is, why we want it, and how to use it. In this chapter we'll learn what Dependency Injection is, why we want it, and how to use it.
<a name="why-di"></a> <a name="why-di"></a>
.l-main-section .l-main-section
:markdown :marked
## Why Dependency Injection? ## Why Dependency Injection?
Let's start with the following code. Let's start with the following code.
@ -95,7 +95,7 @@ include ../../../../_includes/_util-fns
If someone extends the `Engine` class, that is not `Car`'s problem. If someone extends the `Engine` class, that is not `Car`'s problem.
.l-sub-section .l-sub-section
:markdown :marked
The consumer of `Car` has the problem. The consumer must update the car creation code to The consumer of `Car` has the problem. The consumer must update the car creation code to
something like: something like:
``` ```
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
The critical point is this: `Car` itself did not have to change. The critical point is this: `Car` itself did not have to change.
We'll take care of the consumer's problem soon enough. We'll take care of the consumer's problem soon enough.
:markdown :marked
The `Car` class is much easier to test because we are in complete control The `Car` class is much easier to test because we are in complete control
of its dependencies. of its dependencies.
We can pass mocks to the constructor that do exactly what we want them to do We can pass mocks to the constructor that do exactly what we want them to do
@ -163,7 +163,7 @@ include ../../../../_includes/_util-fns
let's see how it is implemented in Angular. let's see how it is implemented in Angular.
.l-main-section .l-main-section
:markdown :marked
## Angular Dependency Injection ## Angular Dependency Injection
Angular ships with its own Dependency Injection framework. This framework can also be used Angular ships with its own Dependency Injection framework. This framework can also be used
@ -200,9 +200,9 @@ include ../../../../_includes/_util-fns
Let's make a service that hides how we get Hero data. Let's make a service that hides how we get Hero data.
.l-sub-section .l-sub-section
:markdown :marked
Write this service in its own file. See [this note](#forward-ref) to understand why. Write this service in its own file. See [this note](#forward-ref) to understand why.
:markdown :marked
``` ```
import {Hero} from './hero'; import {Hero} from './hero';
import {HEROES} from './mock-heroes'; import {HEROES} from './mock-heroes';
@ -257,7 +257,7 @@ include ../../../../_includes/_util-fns
``` ```
<a name="di-metadata"></a> <a name="di-metadata"></a>
.l-sub-section .l-sub-section
:markdown :marked
Adding a parameter to the constructor isn't all that's happening here. Adding a parameter to the constructor isn't all that's happening here.
We are writing the app in TypeScript and have followed the parameter name with a type notation, `:HeroService`. We are writing the app in TypeScript and have followed the parameter name with a type notation, `:HeroService`.
@ -269,7 +269,7 @@ include ../../../../_includes/_util-fns
That's how the Angular injector will know to inject an instance of the `HeroService` when it That's how the Angular injector will know to inject an instance of the `HeroService` when it
creates a new `HeroesComponent`. creates a new `HeroesComponent`.
:markdown :marked
### Creating the `HeroesComponent` with the injector (implicitly) ### Creating the `HeroesComponent` with the injector (implicitly)
When we introduced the idea of an injector above, we showed how to create When we introduced the idea of an injector above, we showed how to create
a new `Car` with that injector. a new `Car` with that injector.
@ -341,10 +341,10 @@ include ../../../../_includes/_util-fns
**The `@Injectable()` decoration catches our eye!** **The `@Injectable()` decoration catches our eye!**
.alert.is-critical .alert.is-critical
:markdown :marked
**Always include the parentheses!** Always call `@Injectable()`. It's easy to forget the parentheses. **Always include the parentheses!** Always call `@Injectable()`. It's easy to forget the parentheses.
Our application will fail mysteriously if we do. It bears repeating: **always include the parentheses.** Our application will fail mysteriously if we do. It bears repeating: **always include the parentheses.**
:markdown :marked
We haven't seen `@Injectable()` before. We haven't seen `@Injectable()` before.
As it happens, we could have added it to `HeroService`. We didn't bother because we didn't need it then. As it happens, we could have added it to `HeroService`. We didn't bother because we didn't need it then.
@ -357,7 +357,7 @@ include ../../../../_includes/_util-fns
TypeScript generates metadata for *any* class with a decorator and *any* decorator will do. TypeScript generates metadata for *any* class with a decorator and *any* decorator will do.
.l-main-section .l-main-section
:markdown :marked
<a name="providers"></a> <a name="providers"></a>
## Injector Providers ## Injector Providers
@ -468,13 +468,13 @@ include ../../../../_includes/_util-fns
} }
``` ```
.l-sub-section .l-sub-section
:markdown :marked
The factory takes two parameters: the logger service and a user service. The factory takes two parameters: the logger service and a user service.
The logger we pass straight to the constructor as we did before. The logger we pass straight to the constructor as we did before.
We'll know to use the cool new feature if the `userService.user.isSpecial` flag is true, We'll know to use the cool new feature if the `userService.user.isSpecial` flag is true,
a fact we can't know until runtime. a fact we can't know until runtime.
:markdown :marked
We use dependency injection everywhere so of course the factory function depends on We use dependency injection everywhere so of course the factory function depends on
two injected services: `Logger` and `UserService`. two injected services: `Logger` and `UserService`.
We declare those requirements in our provider definition object: We declare those requirements in our provider definition object:
@ -485,12 +485,12 @@ include ../../../../_includes/_util-fns
}; };
``` ```
.l-sub-section .l-sub-section
:markdown :marked
The `useFactory` field tells Angular that the provider is a factory function and that its implementation is the `heroServiceFactory`. The `useFactory` field tells Angular that the provider is a factory function and that its implementation is the `heroServiceFactory`.
The `deps` property is an array of [provider tokens](#token). The `deps` property is an array of [provider tokens](#token).
The `Logger` and `UserService` classes serve as tokens for their own class providers. The `Logger` and `UserService` classes serve as tokens for their own class providers.
:markdown :marked
Finally, we create the provider and adjust the bootstrapping to include that provider Finally, we create the provider and adjust the bootstrapping to include that provider
among its provider registrations. among its provider registrations.
``` ```
@ -552,7 +552,7 @@ include ../../../../_includes/_util-fns
``` ```
.l-main-section .l-main-section
:markdown :marked
# Next Steps # Next Steps
We learned the basics of Angular Dependency Injection in this chapter. We learned the basics of Angular Dependency Injection in this chapter.
@ -563,7 +563,7 @@ include ../../../../_includes/_util-fns
.l-main-section .l-main-section
<a name="forward-ref"></a> <a name="forward-ref"></a>
:markdown :marked
### Appendix: Why we recommend one class per file ### Appendix: Why we recommend one class per file
Developers expect one class per file. Multiple classes per file is confusing and is best avoided. Developers expect one class per file. Multiple classes per file is confusing and is best avoided.
If we define every class in its own file, there is nothing in this note to worry about. If we define every class in its own file, there is nothing in this note to worry about.
@ -588,7 +588,7 @@ include ../../../../_includes/_util-fns
alert(HeroesComponent.$providers) alert(HeroesComponent.$providers)
``` ```
.l-sub-section .l-sub-section
:markdown :marked
The `HeroService` is incorrectly defined below the `HeroComponent`. The `HeroService` is incorrectly defined below the `HeroComponent`.
The `$providers` static property represents the metadata about the injected `HeroService` The `$providers` static property represents the metadata about the injected `HeroService`
@ -596,7 +596,7 @@ include ../../../../_includes/_util-fns
The `alert` simulates the action of the Dependency Injector at runtime The `alert` simulates the action of the Dependency Injector at runtime
when it attempts to create a `HeroesComponent`. when it attempts to create a `HeroesComponent`.
:markdown :marked
Run it. The alert appears but displays nothing. Run it. The alert appears but displays nothing.
This is the equivalent of the null reference error thrown at runtime. This is the equivalent of the null reference error thrown at runtime.

View File

@ -2,7 +2,7 @@ include ../../../../_includes/_util-fns
<!-- http://plnkr.co/edit/x9JYbC --> <!-- http://plnkr.co/edit/x9JYbC -->
:markdown :marked
## Displaying Component Properties ## Displaying Component Properties
We typically display data in Angular by binding controls in an HTML template We typically display data in Angular by binding controls in an HTML template
@ -17,7 +17,7 @@ figure.image-display
img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI") img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI")
.l-main-section .l-main-section
:markdown :marked
## Showing component properties with interpolation ## Showing component properties with interpolation
The easiest way to display a component property The easiest way to display a component property
is to bind the property name through interpolation. is to bind the property name through interpolation.
@ -32,7 +32,7 @@ figure.image-display
+makeExample('displaying-data/ts/src/app/app.1.ts') +makeExample('displaying-data/ts/src/app/app.1.ts')
:markdown :marked
We added two properties to the formerly empty component: `title` and `myHero`. We added two properties to the formerly empty component: `title` and `myHero`.
Our revised template displays the two component properties using the double curly brace Our revised template displays the two component properties using the double curly brace
@ -40,24 +40,24 @@ figure.image-display
+makeExample('displaying-data/ts/src/app/app.1.ts', 'template') +makeExample('displaying-data/ts/src/app/app.1.ts', 'template')
.l-sub-section .l-sub-section
:markdown :marked
The template is a multi-line string within ECMAScript 2015 back-tics (\`). The template is a multi-line string within ECMAScript 2015 back-tics (\`).
The back-tick (\`) is not the same character as a single quote ('). The back-tick (\`) is not the same character as a single quote (').
It has many nice features. The feature we're exploiting is It has many nice features. The feature we're exploiting is
the ability to compose the string over several lines which the ability to compose the string over several lines which
makes for much more readable HTML. makes for much more readable HTML.
:markdown :marked
Angular automatically pulls the value of the `title` and `myHero` properties from the component and Angular automatically pulls the value of the `title` and `myHero` properties from the component and
inserts those values into the browser. Angular will update the display inserts those values into the browser. Angular will update the display
when these properties change. when these properties change.
.l-sub-section .l-sub-section
:markdown :marked
More precisely, the re-display occurs after some kind of asynchronous event related to More precisely, the re-display occurs after some kind of asynchronous event related to
the view such as a keystroke, a timer completion, or an asynch `XHR` response. the view such as a keystroke, a timer completion, or an asynch `XHR` response.
We don't have those in this sample. We don't have those in this sample.
But then the properties aren't changing on their own either. For the moment we must operate on faith. But then the properties aren't changing on their own either. For the moment we must operate on faith.
:markdown :marked
Notice that we haven't called **new** to create an instance of the `AppComponent` class. Notice that we haven't called **new** to create an instance of the `AppComponent` class.
Angular is creating an instance for us. How? Angular is creating an instance for us. How?
@ -65,7 +65,7 @@ figure.image-display
Remember back in QuickStart that we added the `<my-app>` element to the body of our `index.html` Remember back in QuickStart that we added the `<my-app>` element to the body of our `index.html`
+makeExample('displaying-data/ts/src/index.html', 'my-app') +makeExample('displaying-data/ts/src/index.html', 'my-app')
:markdown :marked
When we bootstrap with the `AppComponent` class (see the bottom of `app.ts`), Angular looks for a `<my-app>` When we bootstrap with the `AppComponent` class (see the bottom of `app.ts`), Angular looks for a `<my-app>`
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
inside the `<my-app>` tag. inside the `<my-app>` tag.
@ -90,40 +90,40 @@ figure.image-display
Some folks prefer to declare the properties and initialize them within a constructor like this: Some folks prefer to declare the properties and initialize them within a constructor like this:
+makeExample('displaying-data/ts/src/app/app-ctor.ts', 'app-ctor') +makeExample('displaying-data/ts/src/app/app-ctor.ts', 'app-ctor')
:markdown :marked
That's fine too. The choice between them is a matter of taste and organization policy. That's fine too. The choice between them is a matter of taste and organization policy.
We'll adopt the more terse "variable assignment" style in this chapter simply because We'll adopt the more terse "variable assignment" style in this chapter simply because
there will be less code to read. there will be less code to read.
.l-main-section .l-main-section
:markdown :marked
## Showing an array property with NgFor ## Showing an array property with NgFor
We want to display a list of heroes. We begin by adding a mock heroes name array to the component, We want to display a list of heroes. We begin by adding a mock heroes name array to the component,
just above `myHero` and redefine `myHero` to be the first name in the array. just above `myHero` and redefine `myHero` to be the first name in the array.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'mock-heroes') +makeExample('displaying-data/ts/src/app/app.2.ts', 'mock-heroes')
:markdown :marked
Now we use the Angular `NgFor` "repeater" Directive in the template to display Now we use the Angular `NgFor` "repeater" Directive in the template to display
each item in the `heroes` list. each item in the `heroes` list.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'template') +makeExample('displaying-data/ts/src/app/app.2.ts', 'template')
:markdown :marked
Our presentation is the familiar HTML unordered list with `<ul>` and `<li>` tags. Let's focus on the `<li>` tag. Our presentation is the familiar HTML unordered list with `<ul>` and `<li>` tags. Let's focus on the `<li>` tag.
+makeExample('displaying-data/ts/src/app/app.2.ts', 'li-repeater') +makeExample('displaying-data/ts/src/app/app.2.ts', 'li-repeater')
:markdown :marked
We added a somewhat mysterious `*ng-for` to the `<li>` element. We added a somewhat mysterious `*ng-for` to the `<li>` element.
That's the Angular "repeater" directive. That's the Angular "repeater" directive.
It's presence on the `<li>` tag marks that `<li>` element (and its children) as the "repeater template". It's presence on the `<li>` tag marks that `<li>` element (and its children) as the "repeater template".
.alert.is-important .alert.is-important
:markdown :marked
Don't forget the leading asterisk (\*) in front of `*ng-for`. It is an essential part of the syntax. Don't forget the leading asterisk (\*) in front of `*ng-for`. It is an essential part of the syntax.
Learn more about this and `NgFor` in the [Template Syntax](./template-syntax.html#ng-for) chapter. Learn more about this and `NgFor` in the [Template Syntax](./template-syntax.html#ng-for) chapter.
:markdown :marked
Notice the `#hero` in the `NgFor` double-quoted instruction. Notice the `#hero` in the `NgFor` double-quoted instruction.
The `#hero` is a "[template local variable](./template-syntax.html#local-vars")" *declaration*. The `#hero` is a "[template local variable](./template-syntax.html#local-vars")" *declaration*.
The (#) prefix declares a local variable name named `hero`. The (#) prefix declares a local variable name named `hero`.
@ -133,11 +133,11 @@ figure.image-display
context for the interpolation in the double curly braces. context for the interpolation in the double curly braces.
.l-sub-section .l-sub-section
:markdown :marked
We happened to give `NgFor` an array to display. We happened to give `NgFor` an array to display.
In fact, `NgFor` can repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) In fact, `NgFor` can repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)
object. object.
:markdown :marked
## Register the NgFor Directive ## Register the NgFor Directive
Angular doesn't know that this template uses the `NgFor` directive. Angular doesn't know that this template uses the `NgFor` directive.
@ -149,20 +149,20 @@ figure.image-display
Look for it in the following: Look for it in the following:
+makeExample('displaying-data/ts/src/app/app.2.ts', 'imports') +makeExample('displaying-data/ts/src/app/app.2.ts', 'imports')
:markdown :marked
Second, we register `NgFor` as a directive accessible to the template by updating the Second, we register `NgFor` as a directive accessible to the template by updating the
`@Component` decorator with a `directives` array property whose only item is `NgFor`: `@Component` decorator with a `directives` array property whose only item is `NgFor`:
+makeExample('displaying-data/ts/src/app/app.2.ts', 'directives') +makeExample('displaying-data/ts/src/app/app.2.ts', 'directives')
:markdown :marked
Now the heroes will appear in the view as an unordered list. Now the heroes will appear in the view as an unordered list.
figure.image-display figure.image-display
img(src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor") img(src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor")
.l-main-section .l-main-section
:markdown :marked
## Creating a class for the data ## Creating a class for the data
We are defining our data directly inside our component. We are defining our data directly inside our component.
@ -177,7 +177,7 @@ figure.image-display
Create a new file called `hero.ts` and add the following short snippet to it. Create a new file called `hero.ts` and add the following short snippet to it.
+makeExample('displaying-data/ts/src/app/hero.ts') +makeExample('displaying-data/ts/src/app/hero.ts')
:markdown :marked
We've defined a class with a constructor and two properties: `id` and `name`. We've defined a class with a constructor and two properties: `id` and `name`.
If we are new to TypeScript, it may not look like we have properties. But we do. We're taking If we are new to TypeScript, it may not look like we have properties. But we do. We're taking
@ -186,30 +186,30 @@ figure.image-display
Consider the first parameter: Consider the first parameter:
+makeExample('displaying-data/ts/src/app/hero.ts', 'id-parameter') +makeExample('displaying-data/ts/src/app/hero.ts', 'id-parameter')
:markdown :marked
That brief syntax simultaneously That brief syntax simultaneously
* declares a constructor parameter and its type * declares a constructor parameter and its type
* declare a public property of the same name * declare a public property of the same name
* initializes that property with the corresponding argument when we "new" an instance of the class. * initializes that property with the corresponding argument when we "new" an instance of the class.
.l-main-section .l-main-section
:markdown :marked
## Use the Hero class ## Use the Hero class
Let's redefine the heroes property in our component to return an array of these Heroes Let's redefine the heroes property in our component to return an array of these Heroes
and also set the `myHero` property with the first of these mock heroes. and also set the `myHero` property with the first of these mock heroes.
+makeExample('displaying-data/ts/src/app/app.3.ts', 'heroes') +makeExample('displaying-data/ts/src/app/app.3.ts', 'heroes')
:markdown :marked
We'll have to update the template. We'll have to update the template.
At the moment it displays the entire hero object which used to be a string value. At the moment it displays the entire hero object which used to be a string value.
Let's fix that so we interpolate the `hero.name` property Let's fix that so we interpolate the `hero.name` property
+makeExample('displaying-data/ts/src/app/app.3.ts', 'template') +makeExample('displaying-data/ts/src/app/app.3.ts', 'template')
:markdown :marked
Our display looks the same but we know how much better it is under the hood. Our display looks the same but we know how much better it is under the hood.
.l-main-section .l-main-section
:markdown :marked
## Conditional display with NgIf ## Conditional display with NgIf
Sometimes the app should display a view or a portion of a view only under prescribed circumstances. Sometimes the app should display a view or a portion of a view only under prescribed circumstances.
@ -220,38 +220,38 @@ figure.image-display
We can see it in action by adding the following paragraph at the bottom of the template: We can see it in action by adding the following paragraph at the bottom of the template:
+makeExample('displaying-data/ts/src/app/app.final.ts', 'message') +makeExample('displaying-data/ts/src/app/app.final.ts', 'message')
.alert.is-important .alert.is-important
:markdown :marked
Don't forget the leading asterisk (\*) in front of `*ng-if`. It is an essential part of the syntax. Don't forget the leading asterisk (\*) in front of `*ng-if`. It is an essential part of the syntax.
Learn more about this and `NgIf` in the [Template Syntax](./template-syntax.html#ng-if) chapter. Learn more about this and `NgIf` in the [Template Syntax](./template-syntax.html#ng-if) chapter.
:markdown :marked
The [template expression](./template-syntax.html#template-expressions) inside the double quotes The [template expression](./template-syntax.html#template-expressions) inside the double quotes
looks much like JavaScript and it is much like JavaScript. looks much like JavaScript and it is much like JavaScript.
When the component's list of heroes has more than 3 items, Angular adds the paragraph to the DOM and the message appears. When the component's list of heroes has more than 3 items, Angular adds the paragraph to the DOM and the message appears.
If there were 3 or fewer items, Angular omits the the paragraph and there is no message. If there were 3 or fewer items, Angular omits the the paragraph and there is no message.
.alert.is-helpful .alert.is-helpful
:markdown :marked
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM.
That hardly matters here. It would matter a great deal from a performance perspective if That hardly matters here. It would matter a great deal from a performance perspective if
we were conditionally including or excluding a big chunk of HTML with many data bindings. we were conditionally including or excluding a big chunk of HTML with many data bindings.
:markdown :marked
As with the `NgFor`, we must add the `NgIf` directive to the component's metadata. As with the `NgFor`, we must add the `NgIf` directive to the component's metadata.
We should extend our `import` statement as before ... We should extend our `import` statement as before ...
+makeExample('displaying-data/ts/src/app/app.3.ts', 'import-ng-if') +makeExample('displaying-data/ts/src/app/app.3.ts', 'import-ng-if')
:markdown :marked
... and add it to the directives array: ... and add it to the directives array:
+makeExample('displaying-data/ts/src/app/app.3.ts', 'directives') +makeExample('displaying-data/ts/src/app/app.3.ts', 'directives')
:markdown :marked
Try it out. We have four items in the array so the message should appear. Try it out. We have four items in the array so the message should appear.
Delete one of the elements from the array, refresh the browser, and the message should no longer appear. Delete one of the elements from the array, refresh the browser, and the message should no longer appear.
.l-main-section .l-main-section
:markdown :marked
## Use the CORE_DIRECTIVES Constant ## Use the CORE_DIRECTIVES Constant
There are other core Angular directives, such as `NgClass` and `NgSwitch`, There are other core Angular directives, such as `NgClass` and `NgSwitch`,
@ -266,15 +266,15 @@ figure.image-display
We'll revise our `import` statement one last time. We'll revise our `import` statement one last time.
+makeExample('displaying-data/ts/src/app/app.final.ts', 'imports') +makeExample('displaying-data/ts/src/app/app.final.ts', 'imports')
:markdown :marked
and update the `directives` metadata and update the `directives` metadata
+makeExample('displaying-data/ts/src/app/app.final.ts', 'directives') +makeExample('displaying-data/ts/src/app/app.final.ts', 'directives')
:markdown :marked
Pro tip: we register this constant in almost every template we write. Pro tip: we register this constant in almost every template we write.
.l-main-section .l-main-section
:markdown :marked
## Summary ## Summary
Now we know how to Now we know how to
- use **interpolation** with the double curly braces to display a component property, - use **interpolation** with the double curly braces to display a component property,
@ -291,7 +291,7 @@ figure.image-display
'app.ts, hero.ts') 'app.ts, hero.ts')
.l-main-section .l-main-section
:markdown :marked
## Next Steps ## Next Steps
In addition to displaying data, most applications need to respond to user input. In addition to displaying data, most applications need to respond to user input.
Learn about that in the [User Input](./user-input.html) chapter. Learn about that in the [User Input](./user-input.html) chapter.

View File

@ -1,7 +1,7 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
<!-- http://plnkr.co/edit/wg154K --> <!-- http://plnkr.co/edit/wg154K -->
:markdown :marked
Weve all used a form to login, submit a help request, place an order, book a flight, Weve all used a form to login, submit a help request, place an order, book a flight,
schedule a meeting and perform countless other data entry tasks. schedule a meeting and perform countless other data entry tasks.
Forms are the mainstay of business applications. Forms are the mainstay of business applications.
@ -31,15 +31,15 @@ include ../../../../_includes/_util-fns
- how to share information across controls with template local variables - how to share information across controls with template local variables
.l-main-section .l-main-section
:markdown :marked
## Template-Driven Forms ## Template-Driven Forms
Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with 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 chapter. the form-specific Directives and techniques described in this chapter.
.l-sub-section .l-sub-section
:markdown :marked
That's not the only way to create a form but it's the way we'll cover in this chapter. That's not the only way to create a form but it's the way we'll cover in this chapter.
:markdown :marked
We can build almost any form we need with an Angular template ... login forms, contact forms ... pretty much any business forms. We can build almost any form we need with an Angular template ... login forms, contact forms ... pretty much any business forms.
We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, 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. conditionally enable or disable specific controls, trigger built-in visual feedback, and much more.
@ -52,7 +52,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/hf-1.png" alt="Clean Form") img(src="/resources/images/devguide/forms/hf-1.png" alt="Clean Form")
:markdown :marked
Here at the *Hero Employment Agency* we use this form to maintain personal information about the Here at the *Hero Employment Agency* we use this form to maintain personal information about the
heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis!
@ -63,13 +63,13 @@ figure.image-display
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/hf-2.png" alt="Invalid, Name Required") img(src="/resources/images/devguide/forms/hf-2.png" alt="Invalid, Name Required")
:markdown :marked
Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red. Note that the submit button is disabled and the "required" bar to the left of the input control changed from green to red.
.l-sub-section .l-sub-section
p We'll' customize the colors and location of the "required" bar with standard CSS. p We'll' customize the colors and location of the "required" bar with standard CSS.
:markdown :marked
We will build this form in the following sequence of small steps We will build this form in the following sequence of small steps
1. Create the `Hero` model class 1. Create the `Hero` model class
@ -82,7 +82,7 @@ figure.image-display
1. Handle form submission with **ng-submit** 1. Handle form submission with **ng-submit**
1. Disable the forms submit button until the form is valid 1. Disable the forms submit button until the form is valid
:markdown :marked
## Setup ## Setup
Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html). Create a new project folder (`angular2-forms`) and follow the steps in the [QuickStart](../quickstart.html).
@ -99,7 +99,7 @@ figure.image-display
+makeExample('forms/ts/src/app/hero.ts') +makeExample('forms/ts/src/app/hero.ts')
:markdown :marked
It's an anemic model with few requirements and no behavior. Perfect for our demo. 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 The TypeScript compiler generates a public field for each `public` constructor parameter and
@ -111,7 +111,7 @@ figure.image-display
The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`. The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
.l-main-section .l-main-section
:markdown :marked
## Create a Form component ## Create a Form component
An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions. An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions.
@ -122,7 +122,7 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.ts', 'first') +makeExample('forms/ts/src/app/hero-form.component.ts', 'first')
:markdown :marked
Theres nothing special about this component, nothing to distinguish it from any component we've written before, Theres nothing special about this component, nothing to distinguish it from any component we've written before,
nothing form-specific about it ... except, perhaps, the tell-tale `FORM_DIRECTIVES` import. nothing form-specific about it ... except, perhaps, the tell-tale `FORM_DIRECTIVES` import.
@ -155,7 +155,7 @@ figure.image-display
We made a good choice to put the HTML template elsewhere. Let's write it. We made a good choice to put the HTML template elsewhere. Let's write it.
.l-main-section .l-main-section
:markdown :marked
## Revise the *app.ts* ## Revise the *app.ts*
`app.ts` is the application's root component. It will host our new `HeroFormComponent`. `app.ts` is the application's root component. It will host our new `HeroFormComponent`.
@ -163,9 +163,9 @@ figure.image-display
Replace the contents of the "QuickStart" version with the following: Replace the contents of the "QuickStart" version with the following:
+makeExample('forms/ts/src/app/app.ts') +makeExample('forms/ts/src/app/app.ts')
:markdown :marked
.l-sub-section .l-sub-section
:markdown :marked
There are only three changes: There are only three changes:
1. We import the new `HeroFormComponent`. 1. We import the new `HeroFormComponent`.
@ -176,14 +176,14 @@ figure.image-display
which is itself a Directive (as are all Components). which is itself a Directive (as are all Components).
.l-main-section .l-main-section
:markdown :marked
## Create an initial HTML Form Template ## Create an initial HTML Form Template
Create a new template file called `hero-form.component.html` and give it the following definition: Create a new template file called `hero-form.component.html` and give it the following definition:
+makeExample('forms/ts/src/app/hero-form.component.html', 'start') +makeExample('forms/ts/src/app/hero-form.component.html', 'start')
:markdown :marked
That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and 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. opening them up for user input in input boxes.
@ -199,7 +199,7 @@ figure.image-display
Hey, what's a form without a little style! Hey, what's a form without a little style!
.l-sub-section .l-sub-section
:markdown :marked
Since we're using [CSS Boostrap](http://getbootstrap.com/css/). Since we're using [CSS Boostrap](http://getbootstrap.com/css/).
now might be a good time to install it into our project. now might be a good time to install it into our project.
We can do that with npm. We can do that with npm.
@ -207,19 +207,19 @@ figure.image-display
Open a terminal window and enter the command: Open a terminal window and enter the command:
code-example(language="html" escape="html"). code-example(language="html" escape="html").
npm install bootstrap npm install bootstrap
:markdown :marked
<br>Open the `index.html` and add the following line wherever we like to put our CSS <br>Open the `index.html` and add the following line wherever we like to put our CSS
+makeExample('forms/ts/src/index.html', 'bootstrap')(format=".") +makeExample('forms/ts/src/index.html', 'bootstrap')(format=".")
.callout.is-important .callout.is-important
header Angular Forms Does Not Require A Style Library header Angular Forms Does Not Require A Style Library
:markdown :marked
Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or
the styles of any external library. We are welcome to use the CSS library we choose the styles of any external library. We are welcome to use the CSS library we choose
... or none at all. ... or none at all.
.l-main-section .l-main-section
:markdown :marked
## Add Powers with ***ng-for** ## Add Powers with ***ng-for**
Our hero may choose one super power from a fixed list of Agency-approved powers. Our hero may choose one super power from a fixed list of Agency-approved powers.
We maintain that list internally (in `HeroFormComponent`). We maintain that list internally (in `HeroFormComponent`).
@ -231,19 +231,19 @@ figure.image-display
Add the following HTML *immediately below* the "Alter Ego" group. Add the following HTML *immediately below* the "Alter Ego" group.
+makeExample('forms/ts/src/app/hero-form.component.html', 'powers') +makeExample('forms/ts/src/app/hero-form.component.html', 'powers')
:markdown :marked
We are repeating the `<options>` tag for each power in the list of Powers. We are repeating the `<options>` tag for each power in the list of Powers.
The `#p` local template variable is a different power in each iteration; The `#p` local template variable is a different power in each iteration;
we display its name using the interpolation syntax with the double-curly-braces. we display its name using the interpolation syntax with the double-curly-braces.
.l-main-section .l-main-section
:markdown :marked
## Two-way data binding with ***ng-model** ## Two-way data binding with ***ng-model**
We might be disappointed if we ran the app right now. We might be disappointed if we ran the app right now.
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/hf-3.png" alt="Early form with no binding") img(src="/resources/images/devguide/forms/hf-3.png" alt="Early form with no binding")
:markdown :marked
We quickly realize that we are not binding to the `Hero` yet. We quickly realize that we are not binding to the `Hero` yet.
We know how to do that from earlier chapters. We know how to do that from earlier chapters.
We learned show data on screen with a Property Binding in "[Displaying Data](./displaying-data.html)". We learned show data on screen with a Property Binding in "[Displaying Data](./displaying-data.html)".
@ -262,12 +262,12 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-1') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-1')
.l-sub-section .l-sub-section
:markdown :marked
We appended a diagnostic interpolation after the input tag We appended a diagnostic interpolation after the input tag
so we can see what we're doing. so we can see what we're doing.
We left ourselves a note to throw it way when we're done. We left ourselves a note to throw it way when we're done.
:markdown :marked
Focus on the binding syntax: `[(ng-model)]="..."`. Focus on the binding syntax: `[(ng-model)]="..."`.
If we ran the app right now and started typing in the "Name" input box, If we ran the app right now and started typing in the "Name" input box,
@ -276,7 +276,7 @@ figure.image-display
At some point it might look like this. At some point it might look like this.
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/ng-model-in-action.png" alt="ng-model in action") img(src="/resources/images/devguide/forms/ng-model-in-action.png" alt="ng-model in action")
:markdown :marked
The diagnostic is evidence that we really are flowing values from the input box to the model and The diagnostic is evidence that we really are flowing values from the input box to the model and
back again. **That's two-way data binding!** back again. **That's two-way data binding!**
@ -290,27 +290,27 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-2') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-2')
:markdown :marked
If we ran the app right now and made a bunch of changes at some point it might look like this. If we ran the app right now and made a bunch of changes at some point it might look like this.
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" alt="ng-model in super action") img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" alt="ng-model in super action")
:markdown :marked
We've changed every Hero model property and the diagnostic near the top of the form We've changed every Hero model property and the diagnostic near the top of the form
confirms that our changes are reflected in the model. confirms that our changes are reflected in the model.
** We're done with the diagnostic binding. Delete it now.** ** We're done with the diagnostic binding. Delete it now.**
.alert.is-helpful .alert.is-helpful
:markdown :marked
Although `NgModel` is officially a "Forms" directive we can use `[(ng-model)]` and two-way binding outside of forms too. Although `NgModel` is officially a "Forms" directive we can use `[(ng-model)]` and two-way binding outside of forms too.
:markdown :marked
## Inside [(ng-model)] ## Inside [(ng-model)]
Do we *really want* to know? If we're just happy that it works, move on to the next topic in this chapter. Do we *really want* to know? If we're just happy that it works, move on to the next topic in this chapter.
Otherwise, stick around for this note. Otherwise, stick around for this note.
.l-sub-section .l-sub-section
:markdown :marked
The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on. The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on.
We write a Property Binding to flow data from the model to a target property on screen. We write a Property Binding to flow data from the model to a target property on screen.
@ -328,7 +328,7 @@ figure.image-display
as we do in this re-write of the "Name" `<input>` binding: as we do in this re-write of the "Name" `<input>` binding:
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-3') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-model-3')
:markdown :marked
<br>The Property Binding should feel familiar. The Event Binding might seem strange. <br>The Property Binding should feel familiar. The Event Binding might seem strange.
The name `ng-model-change` is not an event we recognize. The name `ng-model-change` is not an event we recognize.
@ -350,7 +350,7 @@ figure.image-display
[Template Syntax](./template-syntax.html) chapter. [Template Syntax](./template-syntax.html) chapter.
.l-main-section .l-main-section
:markdown :marked
## Track change-state and validity with **ng-control** ## Track change-state and validity with **ng-control**
A form isn't just about data binding. We'd also like to know the state of the controls on our form. A form isn't just about data binding. We'd also like to know the state of the controls on our form.
@ -358,10 +358,10 @@ figure.image-display
.callout.is-helpful .callout.is-helpful
header NgControl requires Form header NgControl requires Form
:markdown :marked
The `NgControl` is one of a family of `NgForm` directives that can only be applied to The `NgControl` is one of a family of `NgForm` directives that can only be applied to
a control within a `<form`> tag. a control within a `<form`> tag.
:markdown :marked
Our application can ask an `NgControl` instance if Our application can ask an `NgControl` instance if
* the user touched the control (`ng-touched` | `ng-untouched`) * the user touched the control (`ng-touched` | `ng-untouched`)
* the value changed (`ng-pristine` | `ng-dirty`) * the value changed (`ng-pristine` | `ng-dirty`)
@ -376,18 +376,18 @@ figure.image-display
we should **add `ng-control`to all three of our form controls**, we should **add `ng-control`to all three of our form controls**,
starting with the "Name" input box starting with the "Name" input box
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-1') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-1')
:markdown :marked
Be sure to assign a unique name to each `ng-control` directive. Be sure to assign a unique name to each `ng-control` directive.
.l-sub-section .l-sub-section
:markdown :marked
Angular registers controls under their `ng-control` names Angular registers controls under their `ng-control` names
with the `NgForm`. with the `NgForm`.
We didn't add the `NgForm` directive explicitly but it's here We didn't add the `NgForm` directive explicitly but it's here
and we'll talk it [later in this chapter](#ng-form). and we'll talk it [later in this chapter](#ng-form).
.l-main-section .l-main-section
:markdown :marked
## Add Custom CSS for Visual Feedback ## Add Custom CSS for Visual Feedback
`NgControl` doesn't just track state. It updates the control with three classes, one `NgControl` doesn't just track state. It updates the control with three classes, one
@ -401,7 +401,7 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-2') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-control-2')
:markdown :marked
If we ran the app, focused our attention on the "Name" input box, and followed the next four steps *precisely* If we ran the app, focused our attention on the "Name" input box, and followed the next four steps *precisely*
1. Look but don't touched 1. Look but don't touched
@ -413,7 +413,7 @@ figure.image-display
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/ng-control-class-changes.png" alt="Invalid Form") img(src="/resources/images/devguide/forms/ng-control-class-changes.png" alt="Invalid Form")
:markdown :marked
The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a The (`ng-valid` | `ng-invalid`) pair are most interesting to us. We want to send a
strong visual signal when the data are invalid and we want to mark required fields. strong visual signal when the data are invalid and we want to mark required fields.
@ -422,17 +422,17 @@ figure.image-display
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/validity-required-indicator.png" alt="Invalid Form") img(src="/resources/images/devguide/forms/validity-required-indicator.png" alt="Invalid Form")
:markdown :marked
We achieve this effect by adding two styles to a new `styles.css` file We achieve this effect by adding two styles to a new `styles.css` file
that we add to our project as a sibling to `index.html`. that we add to our project as a sibling to `index.html`.
+makeExample('forms/ts/src/styles.css') +makeExample('forms/ts/src/styles.css')
:markdown :marked
These styles select for the two Angular validity classes and the HTML 5 "required" attribute. These styles select for the two Angular validity classes and the HTML 5 "required" attribute.
We update the `<head>` of the `index.html` to include this style sheet. We update the `<head>` of the `index.html` to include this style sheet.
+makeExample('forms/ts/src/index.html', 'styles')(format=".") +makeExample('forms/ts/src/index.html', 'styles')(format=".")
:markdown :marked
## Show and Hide Validation Error messages ## Show and Hide Validation Error messages
We can do better. We can do better.
@ -445,14 +445,14 @@ figure.image-display
figure.image-display figure.image-display
img(src="/resources/images/devguide/forms/name-required-error.png" alt="Name required") img(src="/resources/images/devguide/forms/name-required-error.png" alt="Name required")
:markdown :marked
To achieve this effect we extend the `<input>` tag with To achieve this effect we extend the `<input>` tag with
1. a [local template variable](./template-syntax.html#local-vars) 1. a [local template variable](./template-syntax.html#local-vars)
1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid. 1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid.
Here's how we do it for the "name" input box: Here's how we do it for the "name" input box:
+makeExample('forms/ts/src/app/hero-form.component.html', 'name-with-error-msg') +makeExample('forms/ts/src/app/hero-form.component.html', 'name-with-error-msg')
:markdown :marked
We initialized the template local variable with the word "form" (`#name="form"`) We initialized the template local variable with the word "form" (`#name="form"`)
Angular recognizes that syntax and sets the `name` varable Angular recognizes that syntax and sets the `name` varable
@ -464,7 +464,7 @@ figure.image-display
if it becomes invalid, the message is revealed. if it becomes invalid, the message is revealed.
<a id="ng-form"></a> <a id="ng-form"></a>
.l-sub-section .l-sub-section
:markdown :marked
Recall from the previous section that `ng-control` registered this input box with the Recall from the previous section that `ng-control` registered this input box with the
`NgForm` directive as "name". `NgForm` directive as "name".
@ -474,7 +474,7 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.ts', 'directives') +makeExample('forms/ts/src/app/hero-form.component.ts', 'directives')
<br> <br>
:markdown :marked
The `NgForm` directive supplements the the `form` element with additional features. The `NgForm` directive supplements the the `form` element with additional features.
It collects `Controls` (elements identified by an `ng-control` directive) It collects `Controls` (elements identified by an `ng-control` directive)
and monitors their properties including their validity. and monitors their properties including their validity.
@ -484,7 +484,7 @@ figure.image-display
In this example, we are pulling the "name" control out of its `controls` collection In this example, we are pulling the "name" control out of its `controls` collection
and assigning it to the template local variable so that we can and assigning it to the template local variable so that we can
access the control's properties ... such as the control's own `valid` property. access the control's properties ... such as the control's own `valid` property.
:markdown :marked
The "AlterEgo" is optional so we can leave that be. The "AlterEgo" is optional so we can leave that be.
"Power" selection is required. "Power" selection is required.
@ -493,7 +493,7 @@ figure.image-display
power to valid value. power to valid value.
.l-main-section .l-main-section
:markdown :marked
## Submit the form with **ng-submit** ## Submit the form with **ng-submit**
The user should be able to submit this form after filling it in. The user should be able to submit this form after filling it in.
The "Submit" button at the bottom of the form The "Submit" button at the bottom of the form
@ -505,7 +505,7 @@ figure.image-display
and bind it to our `HeroFormComponent.submit()` method with an EventBinding and bind it to our `HeroFormComponent.submit()` method with an EventBinding
+makeExample('forms/ts/src/app/hero-form.component.html', 'ng-submit') +makeExample('forms/ts/src/app/hero-form.component.html', 'ng-submit')
:markdown :marked
We slipped in something extra there at the end! We defined a We slipped in something extra there at the end! We defined a
template local variable, **`#hf`**, and initialized it with the value, "form". template local variable, **`#hf`**, and initialized it with the value, "form".
@ -517,7 +517,7 @@ figure.image-display
the `hf` variable to the button's `disabled` property the `hf` variable to the button's `disabled` property
using an Event Binding. Here's the code: using an Event Binding. Here's the code:
+makeExample('forms/ts/src/app/hero-form.component.html', 'submit-button') +makeExample('forms/ts/src/app/hero-form.component.html', 'submit-button')
:markdown :marked
If we run the application now, we find that the button is enabled. If we run the application now, we find that the button is enabled.
It doesn't do anything useful yet but it's alive. It doesn't do anything useful yet but it's alive.
@ -534,18 +534,18 @@ figure.image-display
2. Reference that variable in a button some 50 lines away. 2. Reference that variable in a button some 50 lines away.
.l-main-section .l-main-section
:markdown :marked
## Toggle two form regions (Extra Credit) ## Toggle two form regions (Extra Credit)
Submitting the form isn't terribly dramatic at the moment. Submitting the form isn't terribly dramatic at the moment.
.l-sub-section .l-sub-section
:markdown :marked
An unsurprising observation for a demo. To be honest, An unsurprising observation for a demo. To be honest,
jazzing it up won't teach us anything new about forms. jazzing it up won't teach us anything new about forms.
But this is an opportunity to exercise some of our newly won But this is an opportunity to exercise some of our newly won
binding skills. binding skills.
If we're not interested, we can skip to the chapter's conclusion If we're not interested, we can skip to the chapter's conclusion
and not miss a thing. and not miss a thing.
:markdown :marked
Let's do something more strikingly visual. Let's do something more strikingly visual.
Let's hide the data entry area and display something else. Let's hide the data entry area and display something else.
@ -554,14 +554,14 @@ figure.image-display
+makeExample('forms/ts/src/app/hero-form.component.html', 'edit-div') +makeExample('forms/ts/src/app/hero-form.component.html', 'edit-div')
:markdown :marked
The main form is visible from the start because the The main form is visible from the start because the
the `submitted` property is false until we submit the form the `submitted` property is false until we submit the form
... as this fragment from the `HeroFormComponent` reminds us: ... as this fragment from the `HeroFormComponent` reminds us:
+makeExample('forms/ts/src/app/hero-form.component.ts', 'submitted') +makeExample('forms/ts/src/app/hero-form.component.ts', 'submitted')
:markdown :marked
When we click the "Submit" button, the `submitted` flag becomes true and the form disappears When we click the "Submit" button, the `submitted` flag becomes true and the form disappears
as planned. as planned.
@ -569,7 +569,7 @@ figure.image-display
Add the following block of HTML below the `<div>` wrapper we just wrote: Add the following block of HTML below the `<div>` wrapper we just wrote:
+makeExample('forms/ts/src/app/hero-form.component.html', 'submitted') +makeExample('forms/ts/src/app/hero-form.component.html', 'submitted')
:markdown :marked
There's our hero again, displayed read-only with interpolation bindings. There's our hero again, displayed read-only with interpolation bindings.
This slug of HTML only appears while the component is in the submitted state. This slug of HTML only appears while the component is in the submitted state.
@ -581,7 +581,7 @@ figure.image-display
That's as much drama as we can muster for now. That's as much drama as we can muster for now.
.l-main-section .l-main-section
:markdown :marked
## Conclusion ## Conclusion
The Angular 2 form discussed in this chapter takes advantage of the following framework features to provide support for data modification, validation and more: The Angular 2 form discussed in this chapter takes advantage of the following framework features to provide support for data modification, validation and more:
@ -612,7 +612,7 @@ figure.image-display
app.ts, app.ts,
index.html, index.html,
styles.css`) styles.css`)
:markdown :marked
Our final project folder structure should look like this: Our final project folder structure should look like this:
``` ```
angular2-forms angular2-forms

View File

@ -1,4 +1,4 @@
:markdown :marked
# Angular 2 Glossary # Angular 2 Glossary
#sg-tables.showcase.shadow-1 #sg-tables.showcase.shadow-1
header.showcase-header header.showcase-header
@ -7,7 +7,7 @@
and the almost right word is the difference between and the almost right word is the difference between
lightning and a lightning bug.</i> - Mark Twain lightning and a lightning bug.</i> - Mark Twain
:markdown :marked
Angular 2 has a vocabulary of its own. Angular 2 has a vocabulary of its own.
Most Angular 2 terms are everyday English words Most Angular 2 terms are everyday English words
with a specific meaning within the Angular system. with a specific meaning within the Angular system.
@ -17,16 +17,16 @@
unexpected definitions. unexpected definitions.
.l-main-section .l-main-section
:markdown :marked
## Annotation ## Annotation
.l-sub-section .l-sub-section
:markdown :marked
In practice a synonym for [Decoration](#decoration). In practice a synonym for [Decoration](#decoration).
:markdown :marked
## Attribute Directive ## Attribute Directive
.l-sub-section .l-sub-section
:markdown :marked
A category of [Directive](#directive) that can listen to and modify the behavior of A category of [Directive](#directive) that can listen to and modify the behavior of
other HTML elements, attributes, properties, and components. They are usually represented other HTML elements, attributes, properties, and components. They are usually represented
as HTML attributes, hence the name. as HTML attributes, hence the name.
@ -35,10 +35,10 @@
an Attribute Directive. an Attribute Directive.
.l-main-section .l-main-section
:markdown :marked
## Binding ## Binding
.l-sub-section .l-sub-section
:markdown :marked
Almost always refers to [Data Binding](#data-binding) and the act of Almost always refers to [Data Binding](#data-binding) and the act of
binding an HTML object property to a data object property. binding an HTML object property to a data object property.
@ -46,10 +46,10 @@
between a "token" or "key" and a dependency [provider](#provider). between a "token" or "key" and a dependency [provider](#provider).
This more rare usage should be clear in context. This more rare usage should be clear in context.
:markdown :marked
## Bootstrap ## Bootstrap
.l-sub-section .l-sub-section
:markdown :marked
We launch an Angular application by "bootstrapping" it with the `bootstrap` method. We launch an Angular application by "bootstrapping" it with the `bootstrap` method.
The `bootstrap` method identifies an application's top level "root" [Component](#component) The `bootstrap` method identifies an application's top level "root" [Component](#component)
and optionally registers service [providers](#provider) with the and optionally registers service [providers](#provider) with the
@ -59,10 +59,10 @@
.l-main-section .l-main-section
:markdown :marked
## Component ## Component
.l-sub-section .l-sub-section
:markdown :marked
An Angular class responsible for exposing data An Angular class responsible for exposing data
to a [View](#view) and handling most of the views display to a [View](#view) and handling most of the views display
and user-interaction logic. and user-interaction logic.
@ -79,10 +79,10 @@
the Component in the role of "Controller" or "View Model". the Component in the role of "Controller" or "View Model".
.l-main-section .l-main-section
:markdown :marked
## Data Binding ## Data Binding
.l-sub-section .l-sub-section
:markdown :marked
Applications display data values to a user and respond to user Applications display data values to a user and respond to user
actions (clicks, touches, keystrokes). actions (clicks, touches, keystrokes).
@ -110,11 +110,11 @@
Learn more about data binding in the Learn more about data binding in the
[Template Syntax](./template-syntax.html#data-binding) chapter. [Template Syntax](./template-syntax.html#data-binding) chapter.
:markdown :marked
<a id="decorator"></a> <a id="decoration"></a> <a id="decorator"></a> <a id="decoration"></a>
## Decorator | Decoration ## Decorator | Decoration
.l-sub-section .l-sub-section
:markdown :marked
A Decorator is a **function** that adds metadata to a class, its members (properties, methods) and function arguments. A Decorator is a **function** that adds metadata to a class, its members (properties, methods) and function arguments.
Decorators are a JavaScript language [feature](https://github.com/wycats/javascript-decorators), implemented in TypeScript and proposed for ES2016 (AKA ES7). Decorators are a JavaScript language [feature](https://github.com/wycats/javascript-decorators), implemented in TypeScript and proposed for ES2016 (AKA ES7).
@ -140,14 +140,14 @@
classes appearing below it in the file. classes appearing below it in the file.
.alert.is-important .alert.is-important
:markdown :marked
Always include the parentheses `()` when applying a decorator. Always include the parentheses `()` when applying a decorator.
A decorator is a **function** that must be called when applied. A decorator is a **function** that must be called when applied.
:markdown :marked
## Dependency Injection ## Dependency Injection
.l-sub-section .l-sub-section
:markdown :marked
Dependency Injection is both a design pattern and a mechanism Dependency Injection is both a design pattern and a mechanism
for creating and delivering parts of an application to other for creating and delivering parts of an application to other
parts of an application that request them. parts of an application that request them.
@ -198,10 +198,10 @@
There are other opportunities to register as well. There are other opportunities to register as well.
Learn more in the [Dependency Injection](./dependency-injection.html) chapter. Learn more in the [Dependency Injection](./dependency-injection.html) chapter.
:markdown :marked
## Directive ## Directive
.l-sub-section .l-sub-section
:markdown :marked
An Angular class responsible for creating, re-shaping, and interacting with HTML elements An Angular class responsible for creating, re-shaping, and interacting with HTML elements
in the browser DOM. Directives are Angular's most fundamental feature. in the browser DOM. Directives are Angular's most fundamental feature.
@ -232,10 +232,10 @@
elements and their children. elements and their children.
.l-main-section .l-main-section
:markdown :marked
## ECMAScript ## ECMAScript
.l-sub-section .l-sub-section
:markdown :marked
The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript). The [official JavaScript language specification](https://en.wikipedia.org/wiki/ECMAScript).
The latest approved version of JavaScript is The latest approved version of JavaScript is
@ -249,43 +249,43 @@
to ES5 JavaScript. to ES5 JavaScript.
Angular 2 developers may choose to write in ES5 directly. Angular 2 developers may choose to write in ES5 directly.
:markdown :marked
## ECMAScript 2015 ## ECMAScript 2015
.l-sub-section .l-sub-section
:markdown :marked
The lastest released version of JavaScript, The lastest released version of JavaScript,
[ECMAScript 2015](http://www.ecma-international.org/ecma-262/6.0/) [ECMAScript 2015](http://www.ecma-international.org/ecma-262/6.0/)
(AKA "ES2015" or "ES6") (AKA "ES2015" or "ES6")
:markdown :marked
## ES2015 ## ES2015
.l-sub-section .l-sub-section
:markdown :marked
Short hand for "[ECMAScript 2015](#ecmascript=2015)". Short hand for "[ECMAScript 2015](#ecmascript=2015)".
:markdown :marked
## ES6 ## ES6
.l-sub-section .l-sub-section
:markdown :marked
Short hand for "[ECMAScript 2015](#ecmascript=2015)". Short hand for "[ECMAScript 2015](#ecmascript=2015)".
:markdown :marked
## ES5 ## ES5
.l-sub-section .l-sub-section
:markdown :marked
Short hand for "ECMAScript 5", the version of JavaScript run by most modern browsers. Short hand for "ECMAScript 5", the version of JavaScript run by most modern browsers.
See [ECMAScript](#ecmascript). See [ECMAScript](#ecmascript).
.l-main-section .l-main-section
:markdown :marked
## Injector ## Injector
.l-sub-section .l-sub-section
:markdown :marked
An object in the Angular [dependency injection system](#dependency-injection) An object in the Angular [dependency injection system](#dependency-injection)
that can find a named "dependency" in its cache or create such a thing that can find a named "dependency" in its cache or create such a thing
with a registered [provider](#provider). with a registered [provider](#provider).
:markdown :marked
## Input ## Input
.l-sub-section .l-sub-section
:markdown :marked
A directive property that can be the ***target*** of a A directive property that can be the ***target*** of a
[Property Binding](./template-syntax.html#property-binding). [Property Binding](./template-syntax.html#property-binding).
Data values flow *into* this property from the data source identified Data values flow *into* this property from the data source identified
@ -293,10 +293,10 @@
See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter. See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter.
:markdown :marked
## Interpolation ## Interpolation
.l-sub-section .l-sub-section
:markdown :marked
A form of [Property Data Binding](#data-binding) in which a A form of [Property Data Binding](#data-binding) in which a
[template expression](#template-expression) between double-curly braces [template expression](#template-expression) between double-curly braces
renders as text. That text may be concatenated with neighboring text renders as text. That text may be concatenated with neighboring text
@ -306,15 +306,15 @@
code-example(language="html" escape="html"). code-example(language="html" escape="html").
<label>My current hero is {{hero.name}}</label> <label>My current hero is {{hero.name}}</label>
:markdown :marked
Learn more about interpolation in the Learn more about interpolation in the
[Template Syntax](./template-syntax.html#interpolation) chapter. [Template Syntax](./template-syntax.html#interpolation) chapter.
.l-main-section .l-main-section
:markdown :marked
## Output ## Output
.l-sub-section .l-sub-section
:markdown :marked
A directive property that can be the ***target*** of an A directive property that can be the ***target*** of an
[Event Binding](./template-syntax.html#property-binding). [Event Binding](./template-syntax.html#property-binding).
Events stream *out* of this property to the receiver identified Events stream *out* of this property to the receiver identified
@ -323,10 +323,10 @@
See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter. See the [Template Syntax](./template-syntax.html#inputs-outputs) chapter.
.l-main-section .l-main-section
:markdown :marked
## Pipe ## Pipe
.l-sub-section .l-sub-section
:markdown :marked
An Angular pipe is a function that transforms input values to output values for An Angular pipe is a function that transforms input values to output values for
display in a [view](#view). We use the `@Pipe` [decorator](decorator) display in a [view](#view). We use the `@Pipe` [decorator](decorator)
to associate the pipe function with a name. We then can use that to associate the pipe function with a name. We then can use that
@ -337,13 +337,13 @@
code-example(language="html" escape="html"). code-example(language="html" escape="html").
<label>Price: </label>{{product.price | currency}} <label>Price: </label>{{product.price | currency}}
:markdown :marked
Learn more in the chapter on [pipes](./pipes.html) . Learn more in the chapter on [pipes](./pipes.html) .
:markdown :marked
## Provider ## Provider
.l-sub-section .l-sub-section
:markdown :marked
A Provider creates a new instance of a dependency for the Dependency Injection system. A Provider creates a new instance of a dependency for the Dependency Injection system.
It relates a lookup token to code - sometimes called a "recipe" - that can create a dependency value. It relates a lookup token to code - sometimes called a "recipe" - that can create a dependency value.
@ -354,10 +354,10 @@
See [Dependency Injection](#dependency-injection) chapter to learn more. See [Dependency Injection](#dependency-injection) chapter to learn more.
.l-main-section .l-main-section
:markdown :marked
## Router ## Router
.l-sub-section .l-sub-section
:markdown :marked
Most applications consist of many screens or [views](#view). Most applications consist of many screens or [views](#view).
The user navigates among them by clicking links and buttons The user navigates among them by clicking links and buttons
and taking other similar actions that cause the application to and taking other similar actions that cause the application to
@ -368,10 +368,10 @@
of views. of views.
.l-main-section .l-main-section
:markdown :marked
## Structural Directive ## Structural Directive
.l-sub-section .l-sub-section
:markdown :marked
A category of [Directive](#directive) that can A category of [Directive](#directive) that can
shape or re-shape HTML layout, typically by adding, removing, or manipulating shape or re-shape HTML layout, typically by adding, removing, or manipulating
elements and their children. elements and their children.
@ -380,35 +380,35 @@
good examples in this category. good examples in this category.
.l-main-section .l-main-section
:markdown :marked
## Template ## Template
.l-sub-section .l-sub-section
:markdown :marked
A template is a chunk of HTML that Angular uses to render a [view](#view) with A template is a chunk of HTML that Angular uses to render a [view](#view) with
the support and continuing guidance of an Angular [Directive](#directive), the support and continuing guidance of an Angular [Directive](#directive),
most notably a [Component](#component). most notably a [Component](#component).
We write templates in a special [Template Syntax](./template-syntax.html). We write templates in a special [Template Syntax](./template-syntax.html).
:markdown :marked
## Template Expression ## Template Expression
.l-sub-section .l-sub-section
:markdown :marked
An expression in a JavaScript-like syntax that Angular evaluates within An expression in a JavaScript-like syntax that Angular evaluates within
a [data binding](#data-binding). Learn how to write template expressions a [data binding](#data-binding). Learn how to write template expressions
in the [Template Syntax](./template-syntax.html#template-expressions) chapter. in the [Template Syntax](./template-syntax.html#template-expressions) chapter.
:markdown :marked
## Transpile ## Transpile
.l-sub-section .l-sub-section
:markdown :marked
The process of transforming code written in one form of JavaScript The process of transforming code written in one form of JavaScript
(e.g., TypeScript) into another form of JavaScript (e.g., [ES5](#es5)). (e.g., TypeScript) into another form of JavaScript (e.g., [ES5](#es5)).
:markdown :marked
## TypeScript ## TypeScript
.l-sub-section .l-sub-section
:markdown :marked
A version of JavaScript that supports most [ECMAScript 2015](#ecmascript=2015) A version of JavaScript that supports most [ECMAScript 2015](#ecmascript=2015)
language features and many features that may arrive in future versions language features and many features that may arrive in future versions
of JavaScript such as [Decorators](#decorator). of JavaScript such as [Decorators](#decorator).
@ -426,10 +426,10 @@
Learn more about TypeScript on its [website](http://www.typescriptlang.org/). Learn more about TypeScript on its [website](http://www.typescriptlang.org/).
.l-main-section .l-main-section
:markdown :marked
## View ## View
.l-sub-section .l-sub-section
:markdown :marked
A view is a portion of the screen that displays information and responds A view is a portion of the screen that displays information and responds
to user actions such as clicks, mouse moves, and keystrokes. to user actions such as clicks, mouse moves, and keystrokes.
@ -443,10 +443,10 @@
under the control of a [router](#rounter). under the control of a [router](#rounter).
.l-main-section .l-main-section
:markdown :marked
## Zone ## Zone
.l-sub-section .l-sub-section
:markdown :marked
Zones are a mechanism for encapsulating and intercepting Zones are a mechanism for encapsulating and intercepting
a JavaScript application's asynchronous activity. a JavaScript application's asynchronous activity.

View File

@ -1,5 +1,5 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
We learned the basics of Angular Dependency injection in an We learned the basics of Angular Dependency injection in an
[earlier chapter](./dependency-injection.html). [earlier chapter](./dependency-injection.html).
@ -11,7 +11,7 @@ include ../../../../_includes/_util-fns
interesting and useful results. interesting and useful results.
.l-main-section .l-main-section
:markdown :marked
## The Injector Tree ## The Injector Tree
In an [earlier chapter](./dependency-injection.html) In an [earlier chapter](./dependency-injection.html)
@ -25,12 +25,12 @@ include ../../../../_includes/_util-fns
and each component instance in that tree has its own injector! and each component instance in that tree has its own injector!
.l-sub-section .l-sub-section
:markdown :marked
That isn't literally true. Angular is more efficient than that. What is true is that each component instance That isn't literally true. Angular is more efficient than that. What is true is that each component instance
has an injector and that components at different levels in the tree have different injectors. has an injector and that components at different levels in the tree have different injectors.
It is helpful for our purposes to pretend that every component has its own injector. It is helpful for our purposes to pretend that every component has its own injector.
:markdown :marked
Consider a simple variation on the Tour of Heroes application consisting of three different components: Consider a simple variation on the Tour of Heroes application consisting of three different components:
`HeroesApp`, `HeroesListComponent` and `HeroesCardComponent`. `HeroesApp`, `HeroesListComponent` and `HeroesCardComponent`.
The `HeroesApp` holds a single instance of `HeroesListComponent`. The `HeroesApp` holds a single instance of `HeroesListComponent`.
@ -42,7 +42,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src="/resources/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree") img(src="/resources/images/devguide/dependency-injection/component-hierarchy.png" alt="injector tree")
:markdown :marked
Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree. Each component instance gets its own injector and an injector at one level is a child injector of the injector above it in the tree.
When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector. When a component at the bottom requests a dependency, Angular tries to satisfy that dependency with a provider registered in that component's own injector.
@ -52,11 +52,11 @@ figure.image-display
If we run out of ancestors, Angular throws an error. If we run out of ancestors, Angular throws an error.
.l-sub-section .l-sub-section
:markdown :marked
There's a third possibililty. An intermediate component can declare that it is the "host" component. There's a third possibililty. An intermediate component can declare that it is the "host" component.
The hunt for providers will climb no higher than the injector for this host component. The hunt for providers will climb no higher than the injector for this host component.
We'll reserve discussion of this option for another day. We'll reserve discussion of this option for another day.
:markdown :marked
Such a proliferation of injectors makes little sense until we consider the possiblity that injectors at different levels can be Such a proliferation of injectors makes little sense until we consider the possiblity that injectors at different levels can be
configured with different providers. We don't *have* to re-configure providers at every level. But we *can*. configured with different providers. We don't *have* to re-configure providers at every level. But we *can*.
@ -80,7 +80,7 @@ figure.image-display
img(src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="injector tree") img(src="/resources/images/devguide/dependency-injection/injector-tree.png" alt="injector tree")
.l-main-section .l-main-section
:markdown :marked
## Component Injectors ## Component Injectors
In the previous section, we talked about injectors and how they are organized like a tree. Lookups follow the injector tree upwards until they found the requested thing to inject. But when do we actually want to provide bindings on the root injector and when do we want to provide them on a child injector? In the previous section, we talked about injectors and how they are organized like a tree. Lookups follow the injector tree upwards until they found the requested thing to inject. But when do we actually want to provide bindings on the root injector and when do we want to provide them on a child injector?
@ -300,7 +300,7 @@ figure.image-display
.l-main-section .l-main-section
:markdown :marked
## Dependency Visibility ## Dependency Visibility
[TODO] (bindings vs viewBindings) This has been postponed for now until come up with a decent use case [TODO] (bindings vs viewBindings) This has been postponed for now until come up with a decent use case

View File

@ -1,5 +1,5 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
Every application starts out with what seems like a simple task: get data, transform them, and show them to users. Every application starts out with what seems like a simple task: get data, transform them, and show them to users.
Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket. Getting data could be as simple as creating a local variable or as complex as streaming data over a Websocket.
@ -18,7 +18,7 @@ include ../../../../_includes/_util-fns
Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML! Welcome, Angular pipes, the simple display-value transformations that we can declare in our HTML!
.l-main-section .l-main-section
:markdown :marked
## Using Pipes ## Using Pipes
A pipe takes in data as input and transforms it to a desired output. A pipe takes in data as input and transforms it to a desired output.
@ -33,29 +33,29 @@ include ../../../../_includes/_util-fns
+makeExample('pipes/ts/src/app/app.ts', 'hero-birthday') +makeExample('pipes/ts/src/app/app.ts', 'hero-birthday')
:markdown :marked
Focus on the component's template to see how we applied the built-in `DatePipe` Focus on the component's template to see how we applied the built-in `DatePipe`
while binding the `birthday` property. while binding the `birthday` property.
+makeExample('pipes/ts/src/app/app.html', 'hero-birthday-template')(format=".") +makeExample('pipes/ts/src/app/app.html', 'hero-birthday-template')(format=".")
:markdown :marked
Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're Angular [template syntax](./template-syntax.html#pipe) includes a pipe operator ( | ) which we're
using to flow the birthday value on the left through to the `Date` pipe function on the right. using to flow the birthday value on the left through to the `Date` pipe function on the right.
All pipes work this way. All pipes work this way.
.l-main-section .l-main-section
:markdown :marked
## Built-in pipes ## Built-in pipes
Angular comes with a stock set of pipes such as Angular comes with a stock set of pipes such as
`DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`. `DatePipe`, `UpperCasePipe`, `LowerCasePipe`, `CurrencyPipe`, and `PercentPipe`.
They are all immediately available for use in any template. They are all immediately available for use in any template.
.l-sub-section .l-sub-section
:markdown :marked
Learn more about these and many other built-in pipes in the the [API Reference](../api/); Learn more about these and many other built-in pipes in the the [API Reference](../api/);
filter for entries that include the word "pipe". filter for entries that include the word "pipe".
.l-main-section .l-main-section
:markdown :marked
## Parameterizing a Pipe ## Parameterizing a Pipe
A pipe may accept any number of optional parameters to fine-tune its output. A pipe may accept any number of optional parameters to fine-tune its output.
@ -67,7 +67,7 @@ include ../../../../_includes/_util-fns
+makeExample('pipes/ts/src/app/app.html', 'format-birthday')(format=".") +makeExample('pipes/ts/src/app/app.html', 'format-birthday')(format=".")
:markdown :marked
The parameter value can be any valid The parameter value can be any valid
[template expression](./template-expression.html#template-expressions) [template expression](./template-expression.html#template-expressions)
such as a string literal or a component property. such as a string literal or a component property.
@ -76,7 +76,7 @@ include ../../../../_includes/_util-fns
to the component's `format` property. to the component's `format` property.
+makeExample('pipes/ts/src/app/hero-birthday.2.ts', 'hero-birthday2') +makeExample('pipes/ts/src/app/hero-birthday.2.ts', 'hero-birthday2')
:markdown :marked
We also added a button to the template and bound its click event to the component's `toggleFormat` method. We also added a button to the template and bound its click event to the component's `toggleFormat` method.
That method toggles the component's `format` property between a short form That method toggles the component's `format` property between a short form
('shortDate') and a longer form ('fullDate'). ('shortDate') and a longer form ('fullDate').
@ -87,11 +87,11 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle") img(src='/resources/images/devguide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle")
:markdown :marked
.l-sub-section .l-sub-section
:markdown :marked
Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html). Learn more about the `DatePipes` format options in the [API Docs](../api/core/DatePipe-class.html).
:markdown :marked
## Chaining pipes ## Chaining pipes
We can chain pipes together in potentially useful combinations. We can chain pipes together in potentially useful combinations.
In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe` In the following example, we chain the birthday to the `DatePipe` and on to the `UpperCasePipe`
@ -100,7 +100,7 @@ figure.image-display
+makeExample('pipes/ts/src/app/app.html', 'chained-birthday') +makeExample('pipes/ts/src/app/app.html', 'chained-birthday')
:markdown :marked
If we pass a parameter to a filter, we have to add parentheses If we pass a parameter to a filter, we have to add parentheses
to help the template compiler with the evaluation order. to help the template compiler with the evaluation order.
The following example displays The following example displays
@ -112,7 +112,7 @@ figure.image-display
p Future improvements in the template compiler may eliminate the need for parentheses. p Future improvements in the template compiler may eliminate the need for parentheses.
.l-main-section .l-main-section
:markdown :marked
## Custom Pipes ## Custom Pipes
We can write our own custom pipes. We can write our own custom pipes.
@ -127,7 +127,7 @@ figure.image-display
--> -->
+makeExample('pipes/ts/src/app/exponential-strength-pipe.ts') +makeExample('pipes/ts/src/app/exponential-strength-pipe.ts')
:markdown :marked
This pipe definition reveals several few key points This pipe definition reveals several few key points
* We import the `Pipe` decorator from the Angular library (while getting the usual symbols) * We import the `Pipe` decorator from the Angular library (while getting the usual symbols)
* A pipe is a class * A pipe is a class
@ -146,7 +146,7 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster") img(src='/resources/images/devguide/pipes/power-booster.png' alt="Power Booster")
:markdown :marked
Two things to note: Two things to note:
1. We use the pipe in the template expression exactly as we described in the pipe's comments. 1. We use the pipe in the template expression exactly as we described in the pipe's comments.
We pass the value to transform from the left and give our pipe an exponent parameter of `10`. We pass the value to transform from the left and give our pipe an exponent parameter of `10`.
@ -155,12 +155,12 @@ figure.image-display
.callout.is-critical .callout.is-critical
header Remember the pipes array! header Remember the pipes array!
:markdown :marked
Angular reports an error if we neglect to list our custom pipe. Angular reports an error if we neglect to list our custom pipe.
We didn't list the `DatePipe` in our previous example because all We didn't list the `DatePipe` in our previous example because all
Angular built-in pipes are pre-registered. Angular built-in pipes are pre-registered.
Custom pipes must be registered manually. Custom pipes must be registered manually.
:markdown :marked
If we are inclined to try this in a live-coding tool (such a [plunker](http://plnkr.co/)), If we are inclined to try this in a live-coding tool (such a [plunker](http://plnkr.co/)),
we can probe its behavior by changing the value and the optional exponent in the template. we can probe its behavior by changing the value and the optional exponent in the template.
@ -173,10 +173,10 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/pipes/power-boost-calculator.png' alt="Power Boost Calculator") img(src='/resources/images/devguide/pipes/power-boost-calculator.png' alt="Power Boost Calculator")
:markdown :marked
.l-main-section .l-main-section
:markdown :marked
## Stateful Pipes ## Stateful Pipes
There are two categories of pipes, stateless and stateful. There are two categories of pipes, stateless and stateful.
@ -200,7 +200,7 @@ figure.image-display
In the next example, we bind a simple promise to a view with the async pipe. In the next example, we bind a simple promise to a view with the async pipe.
+makeExample('pipes/ts/src/app/app.ts', 'async-message') +makeExample('pipes/ts/src/app/app.ts', 'async-message')
:markdown :marked
The Async pipe saves boilerplate in the component code. The Async pipe saves boilerplate in the component code.
The component doesn't have to subscribe to the async data source, The component doesn't have to subscribe to the async data source,
it doesn't extract the resolved values and expose them for binding, it doesn't extract the resolved values and expose them for binding,
@ -218,11 +218,11 @@ figure.image-display
Here's how we'll decorate our new stateful `FetchJsonPipe` that Here's how we'll decorate our new stateful `FetchJsonPipe` that
makes an HTTP `fetch` request and (eventually) displays the data in the server's response: makes an HTTP `fetch` request and (eventually) displays the data in the server's response:
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts', 'pipe-metadata') +makeExample('pipes/ts/src/app/fetch-json-pipe.ts', 'pipe-metadata')
:markdown :marked
Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file. Immediately below we have the finished pipe. Its input value is an url to an endpoint that returns a JSON file.
The pipe makes a one-time async request to the server and eventually receives the JSON response. The pipe makes a one-time async request to the server and eventually receives the JSON response.
+makeExample('pipes/ts/src/app/fetch-json-pipe.ts') +makeExample('pipes/ts/src/app/fetch-json-pipe.ts')
:markdown :marked
Next we use this pipe in two template bindings where we Next we use this pipe in two template bindings where we
1. display hero names in an `ng-for` repeater 1. display hero names in an `ng-for` repeater
1. chain the fetched results to the built-in `JsonPipe` that renders 1. chain the fetched results to the built-in `JsonPipe` that renders
@ -234,7 +234,7 @@ figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List") img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")
.l-main-section .l-main-section
:markdown :marked
## Next Steps ## Next Steps
Pipes are a great way to encapsulate and share common display-value Pipes are a great way to encapsulate and share common display-value

View File

@ -1,9 +1,9 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
# App Navigation with the Router # App Navigation with the Router
It's coming soon! It's coming soon!
.l-main-section .l-main-section
:markdown :marked
## What's not to love? ## What's not to love?

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
# Template Syntax # Template Syntax
Our Angular application manages what the user sees and does through the interaction of a Component class instance and its user-facing template. Our Angular application manages what the user sees and does through the interaction of a Component class instance and its user-facing template.
@ -37,13 +37,13 @@ include ../../../../_includes/_util-fns
>[Template Expression Operators](#expression-ops) >[Template Expression Operators](#expression-ops)
.l-main-section .l-main-section
:markdown :marked
## HTML ## HTML
HTML is the language of the Angular template. Our “[QuickStart](./quickstart.html)” application had a template that was pure HTML HTML is the language of the Angular template. Our “[QuickStart](./quickstart.html)” application had a template that was pure HTML
code-example(format="" language="html" escape="html"). code-example(format="" language="html" escape="html").
<h3>My First Angular Application</h3> <h3>My First Angular Application</h3>
:markdown :marked
Almost all HTML syntax is valid template syntax. The `<script>` element is a notable exception; it is forbidden in order to eliminate any possibility of JavaScript injection attacks (in practice it is simply ignored). Almost all HTML syntax is valid template syntax. The `<script>` element is a notable exception; it is forbidden in order to eliminate any possibility of JavaScript injection attacks (in practice it is simply ignored).
Some legal HTML doesnt make much sense in a template. The `<html>`, `<body>` and `<base>` elements have no useful role in our repertoire. Pretty much everything else is fair game. Some legal HTML doesnt make much sense in a template. The `<html>`, `<body>` and `<base>` elements have no useful role in our repertoire. Pretty much everything else is fair game.
@ -53,13 +53,13 @@ code-example(format="" language="html" escape="html").
Lets turn to the first form of data binding - interpolation - to see how much richer Template HTML can be. Lets turn to the first form of data binding - interpolation - to see how much richer Template HTML can be.
.l-main-section .l-main-section
:markdown :marked
## Interpolation ## Interpolation
We met the double-curly braces of interpolation, `{{` and `}}`, early in our Angular education. We met the double-curly braces of interpolation, `{{` and `}}`, early in our Angular education.
code-example(format="" language="html" escape="html"). code-example(format="" language="html" escape="html").
<p>My current hero is {{currentHero.firstName}}</p> <p>My current hero is {{currentHero.firstName}}</p>
:markdown :marked
We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments. We use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
code-example(format="" language="html" escape="html"). code-example(format="" language="html" escape="html").
@ -67,7 +67,7 @@ code-example(format="" language="html" escape="html").
{{title}} {{title}}
<img src="{{heroImageUrl}}" height=30> <img src="{{heroImageUrl}}" height=30>
</h3> </h3>
:markdown :marked
The material between the braces is often the name of a component property. Angular replaces that name with the 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 this example, Angular evaluates the `title` and `heroImageUrl` properties string value of the corresponding component property. In this example, Angular evaluates the `title` and `heroImageUrl` properties
and "fills in the blanks", displaying first a bold application title and then a heroic image. and "fills in the blanks", displaying first a bold application title and then a heroic image.
@ -77,7 +77,7 @@ code-example(format="" language="html" escape="html").
code-example(format="" language="html" escape="html"). code-example(format="" language="html" escape="html").
<!-- "The sum of 1 + 1 is 2" --> <!-- "The sum of 1 + 1 is 2" -->
<h1>The sum of 1 + 1 is {{1 + 1}}</h1> <h1>The sum of 1 + 1 is {{1 + 1}}</h1>
:markdown :marked
Angular evaluates all expressions in double curly braces, converts the expression results to strings, and concatenates them with neighboring literal strings. Finally, Angular evaluates all expressions in double curly braces, converts the expression results to strings, and concatenates them with neighboring literal strings. Finally,
it assigns this composite interpolated result to an **element or directive property**. it assigns this composite interpolated result to an **element or directive property**.
@ -89,7 +89,7 @@ code-example(format="" language="html" escape="html").
But before we explore that assertion, well take a closer look at template expressions. But before we explore that assertion, well take a closer look at template expressions.
.l-main-section .l-main-section
:markdown :marked
## Template Expressions ## Template Expressions
We saw a template expression within the interpolation braces. We saw a template expression within the interpolation braces.
Well see template expressions again in [Property Bindings](#property-binding) (`[property]="expression"`) and Well see template expressions again in [Property Bindings](#property-binding) (`[property]="expression"`) and
@ -108,12 +108,12 @@ code-example(format="" language="html" escape="html").
The **expression context** is typically the **component instance** supporting a particular template instance. The **expression context** is typically the **component instance** supporting a particular template instance.
.l-sub-section .l-sub-section
:markdown :marked
We speak of component and template ***instances***. Angular creates multiple concrete instances from a component class and its template. We speak of component and template ***instances***. Angular creates multiple concrete instances from a component class and its template.
For example, we may define a component and template to display a list item and tell Angular to create new instances of that component/template pair for each item in a list. Theres a separate, independent expression context for each item in that list as well. For example, we may define a component and template to display a list item and tell Angular to create new instances of that component/template pair for each item in a list. Theres a separate, independent expression context for each item in that list as well.
:markdown :marked
When we see `title` wrapped in double-curly braces, When we see `title` wrapped in double-curly braces,
we know that it is a property of a parent component. we know that it is a property of a parent component.
When we see `[disabled]="isUnchanged"` or `(click)="onCancel()”`, When we see `[disabled]="isUnchanged"` or `(click)="onCancel()”`,
@ -128,14 +128,14 @@ code-example(format="" language="html" escape="html").
Another is the **`$event`** variable that contains information about an event raised on an element; Another is the **`$event`** variable that contains information about an event raised on an element;
well talk about that when we consider [Event Bindings](#event-binding). well talk about that when we consider [Event Bindings](#event-binding).
.l-sub-section .l-sub-section
:markdown :marked
Although we can write quite complex template expressions, we strongly discourage that practice. Most readers frown on JavaScript in the HTML. 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. Although we can write quite complex template expressions, we strongly discourage that practice. Most readers frown on JavaScript in the HTML. 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.
:markdown :marked
Now that we have a feel for template expressions, were ready to learn about the varieties of data binding syntax beyond Interpolation. Now that we have a feel for template expressions, were ready to learn about the varieties of data binding syntax beyond Interpolation.
.l-main-section .l-main-section
:markdown :marked
<a id="binding-syntax"></a> <a id="binding-syntax"></a>
## Binding syntax overview ## Binding syntax overview
Data binding is a mechanism for coordinating what users see with application data values. While we could push values to and pull values from HTML, Data binding is a mechanism for coordinating what users see with application data values. While we could push values to and pull values from HTML,
@ -178,7 +178,7 @@ table
[(target)] = "expression" [(target)] = "expression"
bindon-target = "expression" bindon-target = "expression"
td Two-way td Two-way
:markdown :marked
**Template expressions must be surrounded in quotes** **Template expressions must be surrounded in quotes**
except for interpolation expressions which must not be quoted. except for interpolation expressions which must not be quoted.
@ -226,7 +226,7 @@ table
We are setting the *properties* of DOM elements, Components, and Directives. We are setting the *properties* of DOM elements, Components, and Directives.
.l-sub-section .l-sub-section
:markdown :marked
### HTML Attribute vs. DOM Property ### HTML Attribute vs. DOM Property
The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works. The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works.
@ -268,18 +268,18 @@ table
**The HTML attribute and the DOM property are not the same thing even when they have the same name.** **The HTML attribute and the DOM property are not the same thing even when they have the same name.**
:markdown :marked
This is so important, well say it again. This is so important, well say it again.
**Template binding works with *properties* and *events*, not *attributes*.** **Template binding works with *properties* and *events*, not *attributes*.**
.callout.is-helpful .callout.is-helpful
header A world without attributes header A world without attributes
:markdown :marked
In the world of Angular 2, the only role of attributes is to initialize element and directive state. In the world of Angular 2, the only role of attributes is to initialize element and directive state.
When we data bind, we're dealing exclusively with element and directive properties and events. When we data bind, we're dealing exclusively with element and directive properties and events.
Attributes effectively disappear. Attributes effectively disappear.
:markdown :marked
With this model firmly in mind, we are ready to discuss the variety of target properties to which we may bind. With this model firmly in mind, we are ready to discuss the variety of target properties to which we may bind.
### Binding Targets ### Binding Targets
@ -348,7 +348,7 @@ table
code-example(format="", language="html"). code-example(format="", language="html").
&lt;button [style.color] = "isSpecial ?'red' : 'green'"&gt; &lt;button [style.color] = "isSpecial ?'red' : 'green'"&gt;
</div> </div>
:markdown :marked
### Spelling target names ### Spelling target names
The target name whether between punctuation or after a prefix - The target name whether between punctuation or after a prefix -
should be spelled with **lowercase**. Although we can spell it in mixed-case, should be spelled with **lowercase**. Although we can spell it in mixed-case,
@ -369,7 +369,7 @@ table
code-example(format="", language="html"). code-example(format="", language="html").
Template parse errors: Template parse errors:
Can't bind to 'textcontent' since it isn't a known native property in ... Can't bind to 'textcontent' since it isn't a known native property in ...
:markdown :marked
Notice that it forced mixed-case ""text**C**ontent" to lowercase "text**c**ontent". Notice that it forced mixed-case ""text**C**ontent" to lowercase "text**c**ontent".
The solution is to write the target property name in “**lower snake case**”, The solution is to write the target property name in “**lower snake case**”,
@ -380,14 +380,14 @@ code-example(format="", language="html").
<hero-detail [is-active] = "isActive"> <hero-detail [is-active] = "isActive">
``` ```
.l-sub-section .l-sub-section
:markdown :marked
According to this rule, we should write `[inner-h-t-m-l]` to access the elements `innerHTML` property. According to this rule, we should write `[inner-h-t-m-l]` to access the elements `innerHTML` property.
Fortunately, the Angular template parser recognizes `inner-html` as an acceptable alias for `innerHTML`. Fortunately, the Angular template parser recognizes `inner-html` as an acceptable alias for `innerHTML`.
:markdown :marked
Lets descend from the architectural clouds and look at each of these binding types in concrete detail. Lets descend from the architectural clouds and look at each of these binding types in concrete detail.
.l-main-section .l-main-section
:markdown :marked
## Property Binding ## Property Binding
We write a template **Property Binding** when we want to set a property of a view element to the value of a template expression. We write a template **Property Binding** when we want to set a property of a view element to the value of a template expression.
@ -429,11 +429,11 @@ code-example(format="", language="html").
<div [ng-class]="special">NgClass is special</div> <div [ng-class]="special">NgClass is special</div>
``` ```
.l-sub-section .l-sub-section
:markdown :marked
Technically, Angular is matching the name to a directive [input](#inputs-outputs), Technically, Angular is matching the name to a directive [input](#inputs-outputs),
one of the property names listed in the directives `inputs` array or a property decorated with `@Input()`. one of the property names listed in the directives `inputs` array or a property decorated with `@Input()`.
Such inputs map to the directives own properties. Such inputs map to the directives own properties.
:markdown :marked
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error. If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
### Property Binding template expressions ### Property Binding template expressions
@ -470,7 +470,7 @@ code-example(language="html").
&lt;h3>The title is {{title}}&lt/h3> &lt;h3>The title is {{title}}&lt/h3>
&lt;h3>[text-content]="'The title is '+title">&lt/h3> &lt;h3>[text-content]="'The title is '+title">&lt/h3>
:markdown :marked
Interpolation is actually a convenient alternative for Property Binding in many cases. Interpolation is actually a convenient alternative for Property Binding in many cases.
In fact, Angular translates those Interpolations into the corresponding Property Bindings In fact, Angular translates those Interpolations into the corresponding Property Bindings
before rendering the view. before rendering the view.
@ -481,7 +481,7 @@ code-example(language="html").
both conforms to the rules and feels most natural for the task at hand. both conforms to the rules and feels most natural for the task at hand.
.l-main-section .l-main-section
:markdown :marked
<a id="other-bindings"></a> <a id="other-bindings"></a>
## Attribute, Class, and Style Bindings ## Attribute, Class, and Style Bindings
The template syntax provides specialized one-way bindings for scenarios less well suited to Property Binding. The template syntax provides specialized one-way bindings for scenarios less well suited to Property Binding.
@ -489,10 +489,10 @@ code-example(language="html").
### Attribute Binding ### Attribute Binding
We can set the value of an attribute directly with an **Attribute Binding**. We can set the value of an attribute directly with an **Attribute Binding**.
.l-sub-section .l-sub-section
:markdown :marked
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 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.
:markdown :marked
We have stressed throughout this chapter 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? We have stressed throughout this chapter 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?
**We must use Attribute Binding when there is no element property to bind.** **We must use Attribute Binding when there is no element property to bind.**
@ -506,12 +506,12 @@ code-example(language="html").
We become painfull aware of this fact when we try to write something like this: We become painfull aware of this fact when we try to write something like this:
code-example(language="html"). code-example(language="html").
&lt;tr>&lt;td colspan="{{1+1}}">Three-Four&lt;/td>&lt;/tr> &lt;tr>&lt;td colspan="{{1+1}}">Three-Four&lt;/td>&lt;/tr>
:markdown :marked
… and get the error: … and get the error:
code-example(format="", language="html"). code-example(format="", language="html").
Template parse errors: Template parse errors:
Can't bind to 'colspan' since it isn't a known native property Can't bind to 'colspan' since it isn't a known native property
:markdown :marked
As the message says, the `<td>` element does not have a `colspan` property. As the message says, the `<td>` element does not have a `colspan` property.
It has the `colspan` attribute but Interpolation and Property Binding set properties, not attributes. It has the `colspan` attribute but Interpolation and Property Binding set properties, not attributes.
@ -562,11 +562,11 @@ code-example(format="", language="html").
<div class="special" [class.special]="!isSpecial">This one is not so special</div> <div class="special" [class.special]="!isSpecial">This one is not so special</div>
``` ```
.l-sub-section .l-sub-section
:markdown :marked
While this is a fine way to toggle a single class name, While this is a fine way to toggle a single class name,
we generally prefer the [NgClass directive](#ng-class) for managing multiple class names at the same time. we generally prefer the [NgClass directive](#ng-class) for managing multiple class names at the same time.
:markdown :marked
### Style Binding ### Style Binding
We can set inline styles with a **Style Binding**. We can set inline styles with a **Style Binding**.
@ -583,12 +583,12 @@ code-example(format="", language="html").
<button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button> <button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
``` ```
.l-sub-section .l-sub-section
:markdown :marked
While this is a fine way to set a single style, While this is a fine way to set a single style,
we generally prefer the [NgStyle directive](#ng-style) for when setting several inline styles at the same time. we generally prefer the [NgStyle directive](#ng-style) for when setting several inline styles at the same time.
.l-main-section .l-main-section
:markdown :marked
## Event Binding ## Event Binding
The bindings weve met so far flow data in one direction *from the component to an element*. The bindings weve met so far flow data in one direction *from the component to an element*.
@ -621,7 +621,7 @@ code-example(format="", language="html").
<input (ng-model-change)="firstName = $event"> <input (ng-model-change)="firstName = $event">
``` ```
.l-sub-section .l-sub-section
:markdown :marked
`ng-model-change` translates to the `ngModelChange` property of the `NgModel` directive. `ng-model-change` translates to the `ngModelChange` property of the `NgModel` directive.
Technically, Angular is matching the target binding name to a directive [output](#inputs-outputs) property, Technically, Angular is matching the target binding name to a directive [output](#inputs-outputs) property,
@ -630,7 +630,7 @@ code-example(format="", language="html").
`ngModelChange` maps to the directive's hidden `update` property. `ngModelChange` maps to the directive's hidden `update` property.
These details are not something we generally need or want to know. These details are not something we generally need or want to know.
:markdown :marked
If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error. 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 expressions ### $event and event handling expressions
@ -689,10 +689,10 @@ code-example(format="", language="html").
Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation. Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), “bubble” events up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
.l-sub-section .l-sub-section
:markdown :marked
`EventEmitter` events dont bubble. `EventEmitter` events dont bubble.
:markdown :marked
The result of an Event Binding expression determines if The result of an Event Binding expression determines if
[event propagation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation) [event propagation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation)
continues or stops with the current element. continues or stops with the current element.
@ -707,7 +707,7 @@ code-example(format="", language="html").
``` ```
.l-main-section .l-main-section
:markdown :marked
<a name="ng-model"></a> <a name="ng-model"></a>
## Two-Way Binding with NgModel ## Two-Way Binding with NgModel
When developing data entry forms we often want to both display a data property and update that property when the user makes changes. When developing data entry forms we often want to both display a data property and update that property when the user makes changes.
@ -745,14 +745,14 @@ code-example(format="", language="html").
``` ```
.l-sub-section .l-sub-section
:markdown :marked
Internally, Angular maps the term, `ng-model`, to an `ng-model` input property and an Internally, Angular maps the term, `ng-model`, to an `ng-model` input property and an
`ng-model-change` output property. `ng-model-change` output property.
Thats a specific example of a more general pattern in which it matches `[(x)]` to an `x` input property Thats a specific example of a more general pattern in which it matches `[(x)]` to an `x` input property
for Property Binding and an `x-change` output property for Event Binding. for Property Binding and an `x-change` output property for Event Binding.
We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so. We can write our own two-way binding directive that follows this pattern if we're ever in the mood to do so.
:markdown :marked
*Before* we can use `NgModel`, we must import it via the `FORM_DIRECTIVES` directives array *Before* we can use `NgModel`, we must import it via the `FORM_DIRECTIVES` directives array
``` ```
import {FORM_DIRECTIVES} from angular2/angular2` import {FORM_DIRECTIVES} from angular2/angular2`
@ -760,7 +760,7 @@ code-example(format="", language="html").
and include that array among the list of directives used by the components template (`directives: [FORM_DIRECTIVES]`). and include that array among the list of directives used by the components template (`directives: [FORM_DIRECTIVES]`).
.l-main-section .l-main-section
:markdown :marked
<a name="directives"></a> <a name="directives"></a>
## Built-in Directives ## Built-in Directives
@ -856,10 +856,10 @@ code-example(format="", language="html").
<hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail> <hero-detail *ng-if="isActive" [hero]="currentHero"></hero-detail>
``` ```
.alert.is-critical .alert.is-critical
:markdown :marked
The leading asterisk (`*`) in front of `ng-if` is a critical part of this syntax. The leading asterisk (`*`) in front of `ng-if` is a critical part of this syntax.
See the section below on [* and &lt;template>](#star-template). See the section below on [* and &lt;template>](#star-template).
:markdown :marked
#### Visibility and NgIf are not the same #### Visibility and NgIf are not the same
We can show and hide an element sub-tree (the element and its children) with a [Class](#class-binding) or a [Style](#style-binding) binding: We can show and hide an element sub-tree (the element and its children) with a [Class](#class-binding) or a [Style](#style-binding) binding:
``` ```
@ -918,9 +918,9 @@ code-example(format="", language="html").
<div *ng-for="#hero of heroes">{{hero.fullName}}</div> <div *ng-for="#hero of heroes">{{hero.fullName}}</div>
``` ```
.alert.is-critical .alert.is-critical
:markdown :marked
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax. See the section below on [* and &lt;template>](#star-template). The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax. See the section below on [* and &lt;template>](#star-template).
:markdown :marked
The `ng-for` directive iterates over the `heroes` array returned by the parent components `heroes` property and stamps out instances of the `<div>` template. The `ng-for` directive iterates over the `heroes` array returned by the parent components `heroes` property and stamps out instances of the `<div>` template.
The quoted text assigned to `ng-for` means “*take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the template instance*”. Angular creates one fresh instance of the `<div>` template for each hero in the array. The quoted text assigned to `ng-for` means “*take each hero in the `heroes` array, store it in the local `hero` variable, and make it available to the template instance*”. Angular creates one fresh instance of the `<div>` template for each hero in the array.
@ -933,13 +933,13 @@ code-example(format="", language="html").
code-example(format="" language="html"). code-example(format="" language="html").
&lt;div *ng-for="#hero of heroes", #i=index">{{i+1}} - {{hero.fullName}}&lt;/div> &lt;div *ng-for="#hero of heroes", #i=index">{{i+1}} - {{hero.fullName}}&lt;/div>
:markdown :marked
We can apply an `ng-for` repeater to Components as well, We can apply an `ng-for` repeater to Components as well,
as we do in this following example with the `LittleHeroComponent`: as we do in this following example with the `LittleHeroComponent`:
code-example(format="" language="html"). code-example(format="" language="html").
&lt;little-hero *ng-for="#hero of heroes" [hero]="hero">&lt;/little-hero> &lt;little-hero *ng-for="#hero of heroes" [hero]="hero">&lt;/little-hero>
:markdown :marked
The template in this case is defined by `LittleHeroComponent` itself. Angular creates a new instance of this component for each hero in the array and assigns the `hero` local *variable* to the `hero`* [input property](#inputs-outputs)* of each instance. The template in this case is defined by `LittleHeroComponent` itself. Angular creates a new instance of this component for each hero in the array and assigns the `hero` local *variable* to the `hero`* [input property](#inputs-outputs)* of each instance.
#### Micro-syntax #### Micro-syntax
@ -948,7 +948,7 @@ code-example(format="" language="html").
Well talk about this in the next section about templates. Well talk about this in the next section about templates.
.l-main-section .l-main-section
:markdown :marked
<a name="star-template"></a> <a name="star-template"></a>
<a name="structural-directive"></a> <a name="structural-directive"></a>
## * and &lt;template> ## * and &lt;template>
@ -1002,14 +1002,14 @@ code-example(format="" language="html").
.callout.is-critical .callout.is-critical
header Remember the brackets! header Remember the brackets!
:markdown :marked
Dont make the mistake of writing `ng-if="isActive"`! Dont make the mistake of writing `ng-if="isActive"`!
That syntax assigns the "isActive" string to the `ng-if` directive. That syntax assigns the "isActive" string to the `ng-if` directive.
In JavaScript a non-empty string is a truthy value so `ng-if` is always In JavaScript a non-empty string is a truthy value so `ng-if` is always
set `true` and always displays `hero-detail` set `true` and always displays `hero-detail`
… even when the parent components `isActive` property returns `false`! … even when the parent components `isActive` property returns `false`!
:markdown :marked
#### Expanding `*ng-for` #### Expanding `*ng-for`
This same transformation applies to `*ng-for`. We can "de-sugar" the syntax ourselves and go from ... This same transformation applies to `*ng-for`. We can "de-sugar" the syntax ourselves and go from ...
``` ```
@ -1036,7 +1036,7 @@ code-example(format="" language="html").
.l-main-section .l-main-section
:markdown :marked
<a id="local-vars"></a> <a id="local-vars"></a>
## Local template variables ## Local template variables
@ -1060,9 +1060,9 @@ code-example(format="" language="html").
combination, creates the variable, and assigns its value. combination, creates the variable, and assigns its value.
.l-sub-section .l-sub-section
:markdown :marked
`var-` is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`. `var-` is the “cannonical” alternative to "#". We could have declared our variable as `var-hero`.
:markdown :marked
We can **reference a local template variable on the same element, on a sibling element, or on We can **reference a local template variable on the same element, on a sibling element, or on
any of its children**. any of its children**.
@ -1111,13 +1111,13 @@ code-example(format="" language="html").
endows it with additional form super powers. endows it with additional form super powers.
.l-sub-section .l-sub-section
:markdown :marked
We know it's the Angular built-in `form` directive We know it's the Angular built-in `form` directive
because we imported the `FORM_DIRECTIVES` collection because we imported the `FORM_DIRECTIVES` collection
and added it to the parent component's `directives` array. and added it to the parent component's `directives` array.
Learn more about forms in the [Forms](./forms.html) chapter. Learn more about forms in the [Forms](./forms.html) chapter.
:markdown :marked
We assign the form object to the `hf` ("hero form") local template variable We assign the form object to the `hf` ("hero form") local template variable
and use it twice. and use it twice.
1. We pass it to the `onSubmit` method of the parent component process form values. 1. We pass it to the `onSubmit` method of the parent component process form values.
@ -1125,7 +1125,7 @@ code-example(format="" language="html").
detect by evaluating `hf.form.valid`. detect by evaluating `hf.form.valid`.
.l-main-section .l-main-section
:markdown :marked
<a id="inputs-outputs"></a> <a id="inputs-outputs"></a>
## Input and Output Properties ## Input and Output Properties
When Directives are the **targets of data binding**, they must expose **input** and **output** properties. When Directives are the **targets of data binding**, they must expose **input** and **output** properties.
@ -1190,7 +1190,7 @@ code-example(format="" language="html").
``` ```
.l-main-section .l-main-section
:markdown :marked
<a id="expression-ops"></a> <a id="expression-ops"></a>
## Template Expression Operators ## Template Expression Operators
The template expression language employs a subset of JavaScript syntax supplemented with some special operators The template expression language employs a subset of JavaScript syntax supplemented with some special operators
@ -1206,37 +1206,37 @@ code-example(format="" language="html").
code-example(format="" language="html"). code-example(format="" language="html").
&lt;!-- Force title to uppercase --> &lt;!-- Force title to uppercase -->
&lt;div>{{ title | uppercase }}&lt;/div> &lt;div>{{ title | uppercase }}&lt;/div>
:markdown :marked
The pipe operator passes the result of an expression on the left to a pipe function on the right. The pipe operator passes the result of an expression on the left to a pipe function on the right.
We can also chain expressions through multiple pipes We can also chain expressions through multiple pipes
code-example(format="" language="html"). code-example(format="" language="html").
&lt;!-- Pipe chaining: force title to uppercase, then to lowercase --> &lt;!-- Pipe chaining: force title to uppercase, then to lowercase -->
&lt;div>{{ title | uppercase | lowercase }}</div> &lt;div>{{ title | uppercase | lowercase }}</div>
:markdown :marked
<a id="elvis"></a> <a id="elvis"></a>
### The Elvis Operator ( ?. ) and null property paths ### The Elvis Operator ( ?. ) and null property paths
The Angular **“Elvis” operator ( ?. )** is a fluent and convenient way to guard against null and undefined values in property paths as we see it here, protecting against a view render failure if the `currentHero` is null. The Angular **“Elvis” operator ( ?. )** is a fluent and convenient way to guard against null and undefined values in property paths as we see it here, protecting against a view render failure if the `currentHero` is null.
code-example(format="" language="html"). code-example(format="" language="html").
<div>The current heros name is {{currentHero?.firstName}}</div> <div>The current heros name is {{currentHero?.firstName}}</div>
:markdown :marked
Lets elaborate on the problem and this particular solution. Lets elaborate on the problem and this particular solution.
What happens when the following data bound `title` property is null? What happens when the following data bound `title` property is null?
code-example(format="" language="html"). code-example(format="" language="html").
<div>The title is {{ title }}</div> <div>The title is {{ title }}</div>
:markdown :marked
The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it. The view still renders but the displayed value is blank; we see only "`The title is`" with nothing after it.
Suppose the template expression involves a property path as in this next example where were displaying the `firstName` of a null hero. Suppose the template expression involves a property path as in this next example where were displaying the `firstName` of a null hero.
code-example(format="" language="html"). code-example(format="" language="html").
<div>The null hero's name is {{nullHero.firstName}}</div> <div>The null hero's name is {{nullHero.firstName}}</div>
:markdown :marked
JavaScript throws a null reference error and so does Angular: JavaScript throws a null reference error and so does Angular:
code-example(format="" language="html"). code-example(format="" language="html").
TypeError: Cannot read property 'firstName' of null in [null] TypeError: Cannot read property 'firstName' of null in [null]
:markdown :marked
Surprisingly, the entire view just disappears. Surprisingly, the entire view just disappears.
We could claim that this is reasonable behavior if we believe that the `hero` property must never be null. We could claim that this is reasonable behavior if we believe that the `hero` property must never be null.
@ -1254,7 +1254,7 @@ code-example(format="" language="html").
code-example(format="" language="html"). code-example(format="" language="html").
&lt;!-- No hero, div not displayed, no error --> &lt;!-- No hero, div not displayed, no error -->
&lt;div *ng-if="nullHero">The null hero's name is {{nullHero?.firstName}}</div> &lt;div *ng-if="nullHero">The null hero's name is {{nullHero?.firstName}}</div>
:markdown :marked
This approach has merit but its cumbersome, especially if the property path is long. This approach has merit but its 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`. Imagine guarding against a null somewhere in a long property path such as `a.b.c.d`.
@ -1262,13 +1262,13 @@ code-example(format="" language="html").
code-example(format="" language="html"). code-example(format="" language="html").
&lt;!-- No hero, no problem! --> &lt;!-- No hero, no problem! -->
&lt;div>The null hero's name is {{nullHero?.firstName}}</div> &lt;div>The null hero's name is {{nullHero?.firstName}}</div>
:markdown :marked
Its great with long property paths too: Its great with long property paths too:
``` ```
a?.b?.c?.d a?.b?.c?.d
``` ```
.l-main-section .l-main-section
:markdown :marked
## What Next? ## What Next?
Weve completed our survey of Template Syntax. Time to put that knowledge to work as we write our own Components and Directives. Weve completed our survey of Template Syntax. Time to put that knowledge to work as we write our own Components and Directives.

View File

@ -1,11 +1,11 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
When the user clicks a link, pushes a button, or types on the keyboard When the user clicks a link, pushes a button, or types on the keyboard
we want to know about it. These user actions all raise DOM events. we want to know about it. These user actions all raise DOM events.
In this chapter we learn to bind to those events using the Angular Event Binding syntax. In this chapter we learn to bind to those events using the Angular Event Binding syntax.
:markdown :marked
## Binding to User Input Events ## Binding to User Input Events
We can listen to [any DOM event](https://developer.mozilla.org/en-US/docs/Web/Events) We can listen to [any DOM event](https://developer.mozilla.org/en-US/docs/Web/Events)
@ -15,7 +15,7 @@ include ../../../../_includes/_util-fns
A click Event Binding makes for a quick illustration. A click Event Binding makes for a quick illustration.
+makeExample('user-input/ts/src/app/app.html', 'click-me-button')(format=".") +makeExample('user-input/ts/src/app/app.html', 'click-me-button')(format=".")
:markdown :marked
The `(click)` to the left of the equal sign identifies the button's click event as the **target of the binding**. The `(click)` to the left of the equal sign identifies the button's click event as the **target of the binding**.
The text within quotes on the right is the "**template expression**" in which we The text within quotes on the right is the "**template expression**" in which we
respond to the click event by calling the component's `onClickMe` method. A [template expression](./template-syntax.html#template-expressions) is a subset respond to the click event by calling the component's `onClickMe` method. A [template expression](./template-syntax.html#template-expressions) is a subset
@ -29,19 +29,19 @@ include ../../../../_includes/_util-fns
These sample can be found in http://plnkr.co/edit/mr63T5 These sample can be found in http://plnkr.co/edit/mr63T5
--> -->
+makeExample('user-input/ts/src/app/app.ts', 'click-me-component') +makeExample('user-input/ts/src/app/app.ts', 'click-me-component')
:markdown :marked
The `onClickMe` in the template refers to the `onClickMe` method of the component. The `onClickMe` in the template refers to the `onClickMe` method of the component.
When the user clicks the button, Angular calls the component's `onClickMe` method. When the user clicks the button, Angular calls the component's `onClickMe` method.
.l-main-section .l-main-section
:markdown :marked
## Get user input from the $event object ## Get user input from the $event object
We can bind to all kinds of events. Let's bind to the "keyup" event of an input box and replay We can bind to all kinds of events. Let's bind to the "keyup" event of an input box and replay
what the user types back onto the screen. what the user types back onto the screen.
This time we'll both listen to an event and grab the user's input. This time we'll both listen to an event and grab the user's input.
+makeExample('user-input/ts/src/app/app.ts', 'key-up-component') +makeExample('user-input/ts/src/app/app.ts', 'key-up-component')
:markdown :marked
Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere. Angular makes an event object available in the **`$event`** variable. The user data we want is in that variable somewhere.
The shape of the `$event` object is determined by whatever raises the event. The shape of the `$event` object is determined by whatever raises the event.
@ -60,10 +60,10 @@ code-example().
a | ab | abc | ab | a | | a | ab | abc | ab | a | |
figure.image-display figure.image-display
img(src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1") img(src='/resources/images/devguide/user-input/keyup1-anim.gif' alt="key up 1")
:markdown :marked
.l-main-section .l-main-section
:markdown :marked
## Get user input from a local template variable ## Get user input from a local template variable
There's another way to get the user data without the `$event` variable. There's another way to get the user data without the `$event` variable.
@ -74,7 +74,7 @@ figure.image-display
Let's demonstrate with a clever keystroke loopback in a single line of template HTML. Let's demonstrate with a clever keystroke loopback in a single line of template HTML.
We don't actually need a dedicated component to do this but we'll make one anyway. We don't actually need a dedicated component to do this but we'll make one anyway.
+makeExample('user-input/ts/src/app/app.ts', 'loop-back-component') +makeExample('user-input/ts/src/app/app.ts', 'loop-back-component')
:markdown :marked
We've declared a template local variable named `box` on the `<input>` element. We've declared a template local variable named `box` on the `<input>` element.
The `box` variable is a reference to the `<input>` element itself which means we can The `box` variable is a reference to the `<input>` element itself which means we can
grab the input element's `value` and display it grab the input element's `value` and display it
@ -93,14 +93,14 @@ figure.image-display
variable than to go through the `$event` object. Maybe we can re-write our previous variable than to go through the `$event` object. Maybe we can re-write our previous
"key-up" example using the variable to acquire the user's' input. Let's give it a try. "key-up" example using the variable to acquire the user's' input. Let's give it a try.
+makeExample('user-input/ts/src/app/app.ts', 'key-up2-component') +makeExample('user-input/ts/src/app/app.ts', 'key-up2-component')
:markdown :marked
That sure seems easier. That sure seems easier.
An especially nice aspect of this approach is that our component code gets clean data values from the view. An especially nice aspect of this approach is that our component code gets clean data values from the view.
It no longer requires knowledge of the `$event` and its structure. It no longer requires knowledge of the `$event` and its structure.
<a id="key-event"></a> <a id="key-event"></a>
.l-main-section .l-main-section
:markdown :marked
## Key event filtering (with `key.enter`) ## Key event filtering (with `key.enter`)
Perhaps we don't care about every keystroke. Perhaps we don't care about every keystroke.
We're only interested in the input box value when the user hits the "Enter" key. We'd like to ignore all other keys. We're only interested in the input box value when the user hits the "Enter" key. We'd like to ignore all other keys.
@ -118,7 +118,7 @@ figure.image-display
img(src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3") img(src='/resources/images/devguide/user-input/keyup3-anim.gif' alt="key up 3")
.l-main-section .l-main-section
:markdown :marked
## On blur ## On blur
Our previous example won't transfer the current state of the input box if the user mouses away and clicks Our previous example won't transfer the current state of the input box if the user mouses away and clicks
@ -130,7 +130,7 @@ figure.image-display
+makeExample('user-input/ts/src/app/app.ts', 'key-up4-component') +makeExample('user-input/ts/src/app/app.ts', 'key-up4-component')
.l-main-section .l-main-section
:markdown :marked
## Put it all together ## Put it all together
We learned how to [display data](./displaying-data.html) in the previous chapter. We learned how to [display data](./displaying-data.html) in the previous chapter.
We've acquired a small arsenal of event binding techniques in this chapter. We've acquired a small arsenal of event binding techniques in this chapter.
@ -142,14 +142,14 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes") img(src='/resources/images/devguide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes")
:markdown :marked
Below is the entire "Little Tour of Heroes" micro-app in a single component. Below is the entire "Little Tour of Heroes" micro-app in a single component.
We'll call out the highlights after we bask briefly in its minimalist glory. We'll call out the highlights after we bask briefly in its minimalist glory.
<!-- <!--
This example in http://plnkr.co/edit/JWeIqq This example in http://plnkr.co/edit/JWeIqq
--> -->
+makeExample('user-input/ts/src/app/app.ts', 'little-tour-of-heroes-app') +makeExample('user-input/ts/src/app/app.ts', 'little-tour-of-heroes-app')
:markdown :marked
We've seen almost everything here before. A few things are new or bear repeating. We've seen almost everything here before. A few things are new or bear repeating.
### **Beware of camelCase variable names** ### **Beware of camelCase variable names**
@ -182,7 +182,7 @@ figure.image-display
.l-main-section .l-main-section
:markdown :marked
## Next Steps ## Next Steps
We've mastered the basic primitives for responding to user input and gestures. We've mastered the basic primitives for responding to user input and gestures.
@ -194,4 +194,3 @@ figure.image-display
in the `Forms` chapter. in the `Forms` chapter.

View File

@ -1,22 +1,22 @@
include ../../../_includes/_util-fns include ../../../_includes/_util-fns
:markdown :marked
Let's start from zero and build a super simple Angular 2 application in TypeScript. Let's start from zero and build a super simple Angular 2 application in TypeScript.
.callout.is-helpful .callout.is-helpful
header Don't want TypeScript? header Don't want TypeScript?
:markdown :marked
Although we're getting started in TypeScript, you can also write Angular 2 apps Although we're getting started in TypeScript, you can also write Angular 2 apps
in JavaScript and Dart by selecting either of those languages from the combo-box in the banner. in JavaScript and Dart by selecting either of those languages from the combo-box in the banner.
.l-main-section .l-main-section
:markdown :marked
## The shortest, quickest ... ## The shortest, quickest ...
Let's put something on the screen in Angular 2 as quickly as we can. Let's put something on the screen in Angular 2 as quickly as we can.
.l-sub-section .l-sub-section
:markdown :marked
While we are about to describe steps to take on your development machine, While we are about to describe steps to take on your development machine,
you could take these same steps in an interactive, online coding environment you could take these same steps in an interactive, online coding environment
such as [plunker](http://plnkr.co/ "Plunker"). You won't have to such as [plunker](http://plnkr.co/ "Plunker"). You won't have to
@ -25,21 +25,21 @@ include ../../../_includes/_util-fns
If you like what you see - and we think you will - you can repeat this If you like what you see - and we think you will - you can repeat this
exercise on your own machine later. exercise on your own machine later.
:markdown :marked
**Create a new folder** to hold our application project, perhaps like this: **Create a new folder** to hold our application project, perhaps like this:
``` ```
mkdir angular2-quickstart mkdir angular2-quickstart
cd angular2-quickstart cd angular2-quickstart
``` ```
.l-main-section .l-main-section
:markdown :marked
## Our first Angular component ## Our first Angular component
**Add a new file** called **`app.ts`** and paste the following lines: **Add a new file** called **`app.ts`** and paste the following lines:
+makeExample('quickstart/ts/src/app/app.ts', null, 'app.ts') +makeExample('quickstart/ts/src/app/app.ts', null, 'app.ts')
:markdown :marked
We've just defined an Angular 2 **component**, We've just defined an Angular 2 **component**,
one of the most important Angular 2 features. one of the most important Angular 2 features.
Components are our primary means of creating application views Components are our primary means of creating application views
@ -52,12 +52,12 @@ include ../../../_includes/_util-fns
Above the class we see the `@Component` decoration. Above the class we see the `@Component` decoration.
.l-sub-section .l-sub-section
:markdown :marked
The `@` symbol before the method name identifies `Component` as a decoration. The `@` symbol before the method name identifies `Component` as a decoration.
A "decoration" is a TypeScript language feature A "decoration" is a TypeScript language feature
for creating metadata about the class. Angular finds this metadata for creating metadata about the class. Angular finds this metadata
in the transpiled JavaScript and responds appropriately. in the transpiled JavaScript and responds appropriately.
:markdown :marked
`@Component` tells Angular that this class *is an Angular component*. `@Component` tells Angular that this class *is an Angular component*.
The configuration object passed to the `@Component` method has two The configuration object passed to the `@Component` method has two
field, a `selector` and a `template`. field, a `selector` and a `template`.
@ -81,7 +81,7 @@ include ../../../_includes/_util-fns
We `import` exactly what we need, as we need it, from named file and library resources. We `import` exactly what we need, as we need it, from named file and library resources.
.l-main-section .l-main-section
:markdown :marked
## Add `index.html` ## Add `index.html`
**Create** an `index.html` file. **Create** an `index.html` file.
@ -90,7 +90,7 @@ include ../../../_includes/_util-fns
+makeExample('quickstart/ts/src/index.1.html', null, 'index.html') +makeExample('quickstart/ts/src/index.1.html', null, 'index.html')
:markdown :marked
We see three noteworthy sections of HTML: We see three noteworthy sections of HTML:
1. We load JavaScript libraries from the web. 1. We load JavaScript libraries from the web.
@ -110,13 +110,13 @@ include ../../../_includes/_util-fns
adorning our `AppComponent` class. adorning our `AppComponent` class.
.l-main-section .l-main-section
:markdown :marked
## Run it! ## Run it!
We need a static file server to serve our application to the browser. We need a static file server to serve our application to the browser.
.l-sub-section .l-sub-section
:markdown :marked
Don't have a static file server handy? Let's install one of our favorites Don't have a static file server handy? Let's install one of our favorites
called [live-server](https://www.npmjs.com/package/live-server "Live-server") called [live-server](https://www.npmjs.com/package/live-server "Live-server")
with the **npm package manager**. with the **npm package manager**.
@ -130,27 +130,27 @@ include ../../../_includes/_util-fns
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm install -g live-server code npm install -g live-server
:markdown :marked
Open a terminal window and enter Open a terminal window and enter
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code live-server code live-server
:markdown :marked
In a few moments, a browser tab should open and display In a few moments, a browser tab should open and display
figure.image-display figure.image-display
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app") img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
:markdown :marked
Congratulations! We are in business. Congratulations! We are in business.
.alert.is-helpful .alert.is-helpful
:markdown :marked
If you see `Loading...` displayed instead, see the If you see `Loading...` displayed instead, see the
[Browser ES6 support appendix](#es6support). [Browser ES6 support appendix](#es6support).
.l-main-section .l-main-section
:markdown :marked
## What's wrong with this? ## What's wrong with this?
We were up and running in a hurry and we could explore Angular We were up and running in a hurry and we could explore Angular
@ -177,7 +177,7 @@ include ../../../_includes/_util-fns
We have tools and procedures for that. We have tools and procedures for that.
.l-main-section .l-main-section
:markdown :marked
## Upping our game ## Upping our game
Let's take a few more steps to put our development on a better foundation. We will Let's take a few more steps to put our development on a better foundation. We will
@ -189,7 +189,7 @@ include ../../../_includes/_util-fns
Shut down the `live-server` running in the terminal window (Ctrl-C) and proceed as follows. Shut down the `live-server` running in the terminal window (Ctrl-C) and proceed as follows.
.l-main-section .l-main-section
:markdown :marked
## Revise the application project structure ## Revise the application project structure
At the moment we're dumping everything into the "angular2-quickstart" **root folder**. At the moment we're dumping everything into the "angular2-quickstart" **root folder**.
@ -205,13 +205,13 @@ include ../../../_includes/_util-fns
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code mkdir src/app code mkdir src/app
:markdown :marked
In Windows: In Windows:
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code mkdir src\app code mkdir src\app
:markdown :marked
**Move `index.html`** into the **`src`** folder. **Move `index.html`** into the **`src`** folder.
**Move `app.ts`** into the **`src/app`** folder. **Move `app.ts`** into the **`src/app`** folder.
@ -226,7 +226,7 @@ include ../../../_includes/_util-fns
``` ```
.l-main-section .l-main-section
:markdown :marked
## Install npm packages locally ## Install npm packages locally
We'll replace the web-based scripts in our `index.html` with We'll replace the web-based scripts in our `index.html` with
@ -261,17 +261,17 @@ include ../../../_includes/_util-fns
+makeJson('quickstart/ts/package.json', { paths: 'name, version, dependencies, devDependencies'}) +makeJson('quickstart/ts/package.json', { paths: 'name, version, dependencies, devDependencies'})
:markdown :marked
There is also a `scripts` section. **Find and replace** it with the following: There is also a `scripts` section. **Find and replace** it with the following:
+makeJson('quickstart/ts/package.json', { paths: 'scripts'}) +makeJson('quickstart/ts/package.json', { paths: 'scripts'})
:markdown :marked
We've just extended our project world with script commands We've just extended our project world with script commands
that we'll be running very soon. that we'll be running very soon.
.l-main-section .l-main-section
:markdown :marked
## Update `index.html` ## Update `index.html`
**Replace** the library scripts section with references to **Replace** the library scripts section with references to
@ -279,13 +279,13 @@ include ../../../_includes/_util-fns
+makeExample('quickstart/ts/src/index.html', 'libraries') +makeExample('quickstart/ts/src/index.html', 'libraries')
:markdown :marked
**Update** the `System` configuration script as follows. **Update** the `System` configuration script as follows.
+makeExample('quickstart/ts/src/index.html', 'systemjs') +makeExample('quickstart/ts/src/index.html', 'systemjs')
.l-sub-section .l-sub-section
:markdown :marked
We won't be transpiling TypeScript in the browser anymore. We won't be transpiling TypeScript in the browser anymore.
We'll do that on our machine and ship the generated JavaScript We'll do that on our machine and ship the generated JavaScript
files to the server. files to the server.
@ -297,19 +297,19 @@ include ../../../_includes/_util-fns
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code import {Foo} from './app/foo' code import {Foo} from './app/foo'
:markdown :marked
`system.js`will know to look for a file named `foo.js` in the `src/app` folder. `system.js`will know to look for a file named `foo.js` in the `src/app` folder.
That's exactly what we're doing in the last line. We're That's exactly what we're doing in the last line. We're
importing our main application file `app` (the generated `app.js` to be precise) importing our main application file `app` (the generated `app.js` to be precise)
from the `src/app/` folder (we moved it there, remember?) from the `src/app/` folder (we moved it there, remember?)
:markdown :marked
Here's the final version Here's the final version
+makeExample('quickstart/ts/src/index.html', null, 'index.html') +makeExample('quickstart/ts/src/index.html', null, 'index.html')
.l-main-section .l-main-section
:markdown :marked
## Prepare for TypeScript Compilation ## Prepare for TypeScript Compilation
### Add the TypeScript configuration file ### Add the TypeScript configuration file
@ -322,12 +322,12 @@ include ../../../_includes/_util-fns
+makeJson('quickstart/ts/src/tsconfig.json', null, 'tsconfig.json') +makeJson('quickstart/ts/src/tsconfig.json', null, 'tsconfig.json')
.alert.is-helpful .alert.is-helpful
:markdown :marked
See the [TypeScript configuration appendix](#tsconfig) to learn more about See the [TypeScript configuration appendix](#tsconfig) to learn more about
this file and these settings. this file and these settings.
.l-main-section .l-main-section
:markdown :marked
## Final structure ## Final structure
Our final project folder structure should look like this: Our final project folder structure should look like this:
``` ```
@ -342,7 +342,7 @@ include ../../../_includes/_util-fns
``` ```
.l-main-section .l-main-section
:markdown :marked
## Compile the TypeScript to JavaScript ## Compile the TypeScript to JavaScript
We no longer transpile TypeScript to JavaScript in the browser. We no longer transpile TypeScript to JavaScript in the browser.
@ -353,7 +353,7 @@ include ../../../_includes/_util-fns
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm run tsc code npm run tsc
:markdown :marked
When it's done we should find the generated *app.js* file in the *src* folder and also an *app.map.js* file that When it's done we should find the generated *app.js* file in the *src* folder and also an *app.map.js* file that
helps debuggers navigate between the JavaScript and the TypeScript source. helps debuggers navigate between the JavaScript and the TypeScript source.
@ -366,7 +366,7 @@ include ../../../_includes/_util-fns
You can stop it anytime with `Ctrl-C`. You can stop it anytime with `Ctrl-C`.
.l-main-section .l-main-section
:markdown :marked
## Run the app! ## Run the app!
Now we are ready to see our app in action. Now we are ready to see our app in action.
@ -378,14 +378,14 @@ include ../../../_includes/_util-fns
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm start code npm start
:markdown :marked
**live-server** loads the browser for us, serves the HTML and JavaScript files, **live-server** loads the browser for us, serves the HTML and JavaScript files,
and displays our application message once more: and displays our application message once more:
figure.image-display figure.image-display
img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app") img(src='/resources/images/devguide/quickstart/my-first-app.png' alt="Output of quickstart app")
:markdown :marked
### Make some changes ### Make some changes
**`live-server`** detects changes to our files and refreshes the browser page for us automatically. **`live-server`** detects changes to our files and refreshes the browser page for us automatically.
@ -397,7 +397,7 @@ include ../../../_includes/_util-fns
Keep `live-server` running in this terminal window. You can stop it anytime with `Ctrl-C`. Keep `live-server` running in this terminal window. You can stop it anytime with `Ctrl-C`.
.l-main-section .l-main-section
:markdown :marked
## What have we done? ## What have we done?
Our first application doesn't do much. It's basically "Hello, World" for Angular 2. Our first application doesn't do much. It's basically "Hello, World" for Angular 2.
@ -428,7 +428,7 @@ include ../../../_includes/_util-fns
<!-- Move this to the Style Guide when we have one --> <!-- Move this to the Style Guide when we have one -->
.l-main-section .l-main-section
:markdown :marked
<a id="tsconfig"></a> <a id="tsconfig"></a>
### Appendix: TypeScript configuration ### Appendix: TypeScript configuration
We added a TypeScript configuration file (`tsconfig.js`) to our project to We added a TypeScript configuration file (`tsconfig.js`) to our project to
@ -465,7 +465,7 @@ include ../../../_includes/_util-fns
``` ```
.l-main-section .l-main-section
:markdown :marked
<a id="es6support"></a> <a id="es6support"></a>
### Appendix: Browser ES6 support ### Appendix: Browser ES6 support
Angular 2 requires ES6 support, such as can be found in most modern Angular 2 requires ES6 support, such as can be found in most modern
@ -478,7 +478,7 @@ include ../../../_includes/_util-fns
code-example(language="sh" format="."). code-example(language="sh" format=".").
npm install es6-shim --save npm install es6-shim --save
:markdown :marked
Now you can load the shim in your `index.html` before the other scripts: Now you can load the shim in your `index.html` before the other scripts:
code-example(language="html" format="."). code-example(language="html" format=".").

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
Well need an Angular application to test, one as simple as possible while having all the angular features we want to test. Well need an Angular application to test, one as simple as possible while having all the angular features we want to test.
<!-- TODO We have such an app that you can download [here](./#). -->Its a one-screen variation on the “Tour of Heroes” that should be familiar to you as a reader of this Developers Guide. <!-- TODO We have such an app that you can download [here](./#). -->Its a one-screen variation on the “Tour of Heroes” that should be familiar to you as a reader of this Developers Guide.
@ -11,7 +11,7 @@ figure.image-display
img(src='/resources/images/devguide/application-under-test/bongos-heroes.png' img(src='/resources/images/devguide/application-under-test/bongos-heroes.png'
style="width:400px;" alt="Bongo's Heroes") style="width:400px;" alt="Bongo's Heroes")
:markdown :marked
At the top is a master list of heroes; at the bottom the detail for the current hero. Click a hero in the list to change the current hero. Change the name in the textbox and that name updates everywhere. The *Update* button modifies the `Hero.name` in an arbitrary way and that change also propagates everywhere on screen. The *Delete* button deletes the hero from the list and a new hero becomes current. *Refresh* clears both the list and detail, then restores the original list of heroes. At the top is a master list of heroes; at the bottom the detail for the current hero. Click a hero in the list to change the current hero. Change the name in the textbox and that name updates everywhere. The *Update* button modifies the `Hero.name` in an arbitrary way and that change also propagates everywhere on screen. The *Delete* button deletes the hero from the list and a new hero becomes current. *Refresh* clears both the list and detail, then restores the original list of heroes.
<!-- TODO You can see a short video of the app in action [here](./#) --> <!-- TODO You can see a short video of the app in action [here](./#) -->
@ -33,6 +33,6 @@ figure.image-display
Well examine the implementation details as we evolve our tests. Well examine the implementation details as we evolve our tests.
.l-main-section .l-main-section
:markdown :marked
## Whats Next? ## Whats Next?
Now that were familiar with how the test app works, were ready to poke at it with our first application tests written in Jasmine. Now that were familiar with how the test app works, were ready to poke at it with our first application tests written in Jasmine.

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
In this chapter well setup the environment for testing our sample application and write a few easy Jasmine tests of the apps simplest parts. In this chapter well setup the environment for testing our sample application and write a few easy Jasmine tests of the apps simplest parts.
We'll learn: We'll learn:
- to test one of our application classes - to test one of our application classes
@ -10,7 +10,7 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Prior Knowledge header Prior Knowledge
:markdown :marked
The Unit Testing chapters build upon each other. We recommend reading them in order. The Unit Testing chapters build upon each other. We recommend reading them in order.
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
we introduced in the [QuickStart](../quickstart.html) and we introduced in the [QuickStart](../quickstart.html) and
@ -18,7 +18,7 @@ include ../../../../_includes/_util-fns
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>. such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
.l-main-section .l-main-section
:markdown :marked
## Create the test-runner HTML ## Create the test-runner HTML
Step away from the Jasmine 101 folder and turn to the root folder of the application that we downloaded in the previous chapter. Step away from the Jasmine 101 folder and turn to the root folder of the application that we downloaded in the previous chapter.
@ -47,7 +47,7 @@ include ../../../../_includes/_util-fns
Were picking up right where we left off. All weve done is change the title. Were picking up right where we left off. All weve done is change the title.
.l-main-section .l-main-section
:markdown :marked
## Update `package.json` for testing ## Update `package.json` for testing
Well assume that the application has `package.json` file that looks more or less like Well assume that the application has `package.json` file that looks more or less like
@ -61,7 +61,7 @@ pre.prettyprint.lang-bash
.alert.is-important Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>! .alert.is-important Be sure to install <code>jasmine-core</code> , not <code>jasmine</code>!
:markdown :marked
Lets make one more change to the `package.json` script commands. Lets make one more change to the `package.json` script commands.
**Open the `package.json` ** and scroll to the `scripts` node. Look for the command named `test`. Change it to: **Open the `package.json` ** and scroll to the `scripts` node. Look for the command named `test`. Change it to:
@ -71,7 +71,7 @@ pre.prettyprint.lang-bash
That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote. That command will launch `live-server` and open a browser to the `unit-tests.html` page we just wrote.
.l-main-section .l-main-section
:markdown :marked
## First app tests ## First app tests
Believe it or not … we could start testing *some* of our app right away. For example, we can test the `Hero` class: Believe it or not … we could start testing *some* of our app right away. For example, we can test the `Hero` class:
@ -135,7 +135,7 @@ pre.prettyprint.lang-bash
The description should be sufficient to identify the tested application part and its source file. Almost any convention will do as long as you and your team follow it consistently and are never confused. The description should be sufficient to identify the tested application part and its source file. Almost any convention will do as long as you and your team follow it consistently and are never confused.
.l-main-section .l-main-section
:markdown :marked
## Run the tests ## Run the tests
Open one terminal window and run the watching compiler command: `npm run tsc` Open one terminal window and run the watching compiler command: `npm run tsc`
@ -149,7 +149,7 @@ figure.image-display
.l-main-section .l-main-section
:markdown :marked
## Critique ## Critique
Is this `Hero` class even worth testing? Its essentially a property bag with almost no logic. Maybe we should have tested the cloning feature. Maybe we should have tested id generation. We didnt bother because there wasnt much to learn by doing that. Is this `Hero` class even worth testing? Its essentially a property bag with almost no logic. Maybe we should have tested the cloning feature. Maybe we should have tested id generation. We didnt bother because there wasnt much to learn by doing that.
@ -161,7 +161,7 @@ figure.image-display
We need to relocate these tests to a separate file. Lets do that next. We need to relocate these tests to a separate file. Lets do that next.
.l-main-section .l-main-section
:markdown :marked
## Where do tests go? ## Where do tests go?
Some people like to keep their tests in a `tests` folder parallel to the application source folder. Some people like to keep their tests in a `tests` folder parallel to the application source folder.
@ -178,7 +178,7 @@ figure.image-display
You may put your tests elsewhere if you wish. Were putting ours inside the app, next to the source files that they test. You may put your tests elsewhere if you wish. Were putting ours inside the app, next to the source files that they test.
.l-main-section .l-main-section
:markdown :marked
## First spec file ## First spec file
**Create** a new file, ** `hero.spec.ts` ** in `src/app` next to `hero.ts`. **Create** a new file, ** `hero.spec.ts` ** in `src/app` next to `hero.ts`.
@ -187,7 +187,7 @@ figure.image-display
.alert.is-important All of our unit test files follow this .spec naming pattern. .alert.is-important All of our unit test files follow this .spec naming pattern.
:markdown :marked
Move the tests we just wrote in`unit-tests.html` to `hero.spec.ts` and convert them from JavaScript into TypeScript: Move the tests we just wrote in`unit-tests.html` to `hero.spec.ts` and convert them from JavaScript into TypeScript:
``` ```
@ -230,7 +230,7 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/first-app-tests/Jasmine-not-running-tests.png' style="width:400px;" alt="Jasmine not running any tests") img(src='/resources/images/devguide/first-app-tests/Jasmine-not-running-tests.png' style="width:400px;" alt="Jasmine not running any tests")
:markdown :marked
Thats Jasmine saying “**things are _so_ bad that _Im not running any tests_.**” Thats Jasmine saying “**things are _so_ bad that _Im not running any tests_.**”
Open the browsers Developer Tools (F12, Ctrl-Shift-i). Theres an error: Open the browsers Developer Tools (F12, Ctrl-Shift-i). Theres an error:
@ -239,7 +239,7 @@ code-example(format="" language="html").
Uncaught ReferenceError: exports is not defined Uncaught ReferenceError: exports is not defined
.l-main-section .l-main-section
:markdown :marked
## Load tests with systemjs ## Load tests with systemjs
The immediate cause of the error is the `export` statement in `hero.ts`. The immediate cause of the error is the `export` statement in `hero.ts`.
@ -296,7 +296,7 @@ figure.image-display
.l-main-section .l-main-section
:markdown :marked
## Observations ## Observations
### System.config ### System.config
@ -326,7 +326,7 @@ figure.image-display
Jasmine re-starts, this time with our imported test queued up. Jasmine re-starts, this time with our imported test queued up.
.l-main-section .l-main-section
:markdown :marked
## Whats Next? ## Whats Next?
We are able to test a part of our application with simple Jasmine tests. We are able to test a part of our application with simple Jasmine tests.
The part was a stand-alone class that made no mention or use of Angular. The part was a stand-alone class that made no mention or use of Angular.

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
We write **unit tests** to explore and confirm the **behavior** of parts of our application. We write **unit tests** to explore and confirm the **behavior** of parts of our application.
We like *having* unit tests for many reasons, three of them in particular: We like *having* unit tests for many reasons, three of them in particular:
@ -22,7 +22,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/unit-testing/spectrum.png' alt="Functional Testing Spectrum") img(src='/resources/images/devguide/unit-testing/spectrum.png' alt="Functional Testing Spectrum")
:markdown :marked
<table style="box-shadow: none"> <table style="box-shadow: none">
<tr> <tr>
<td style="border-bottom: none">Pure unit test</td> <td style="border-bottom: none">Pure unit test</td>
@ -113,12 +113,12 @@ figure.image-display
.callout.is-helpful .callout.is-helpful
header How to Use This Guide header How to Use This Guide
:markdown :marked
The Unit Testing chapters build upon each other. We recommend reading them in order. The Unit Testing chapters build upon each other. We recommend reading them in order.
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
we introduced in the [QuickStart](../quickstart.html) and we introduced in the [QuickStart](../quickstart.html) and
the [Tour of Heroes](../tutorial/) tutorial the [Tour of Heroes](../tutorial/) tutorial
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>. such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
:markdown :marked
Lets get started! Lets get started!

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
Well write our tests with the [Jasmine test framework](http://jasmine.github.io/2.3/introduction.html). Well write our tests with the [Jasmine test framework](http://jasmine.github.io/2.3/introduction.html).
Well start by getting *some* tests to work - *any* tests at all. Well start by getting *some* tests to work - *any* tests at all.
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
**Create a new project folder** perhaps called `angular2-unit-testing`. **Create a new project folder** perhaps called `angular2-unit-testing`.
.l-main-section .l-main-section
:markdown :marked
## Install npm packages locally ## Install npm packages locally
Next follow all of the steps prescribed in “Install npm packages locally” of the Next follow all of the steps prescribed in “Install npm packages locally” of the
@ -24,19 +24,19 @@ pre.prettyprint.lang-bash
code npm install jasmine-core --save-dev --save-exact code npm install jasmine-core --save-dev --save-exact
.alert.is-important .alert.is-important
:markdown :marked
Be sure to install `jasmine-core` , not `jasmine`! Be sure to install `jasmine-core` , not `jasmine`!
:markdown :marked
**Create a sub-folder `src` ** for our tests and then **cd into it**. **Create a sub-folder `src` ** for our tests and then **cd into it**.
We are going to **display and control our tests in the browser**. We are going to **display and control our tests in the browser**.
.l-sub-section .l-sub-section
:markdown :marked
The browser is nice during development of a few tests. Its not the best venue for working with a lot of tests and it wont do at all for build automation. Well switch to the karma test-runner when the time comes. But the browser will do for now. The browser is nice during development of a few tests. Its not the best venue for working with a lot of tests and it wont do at all for build automation. Well switch to the karma test-runner when the time comes. But the browser will do for now.
:markdown :marked
Create a new file called`unit-tests.html` and enter the following: Create a new file called`unit-tests.html` and enter the following:
``` ```
<html> <html>
@ -70,20 +70,20 @@ pre.prettyprint.lang-bash
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/jasmine-1-spec-0-failures.png' style="height:170px;" alt="Jasmine HTML test output") img(src='/resources/images/devguide/jasmine-testing-101/jasmine-1-spec-0-failures.png' style="height:170px;" alt="Jasmine HTML test output")
:markdown :marked
It doesnt get much simpler than that! It doesnt get much simpler than that!
.l-main-section .l-main-section
:markdown :marked
## First TypeScript Test ## First TypeScript Test
Perhaps too simple. We wont write our entire test suite inside one HTML file. Perhaps too simple. We wont write our entire test suite inside one HTML file.
Lets **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** . Lets **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
.l-sub-section .l-sub-section
:markdown :marked
Among Jasmine developers, a test is known as a “spec” and test filenames include the word “spec”. Well stick with that convention. Among Jasmine developers, a test is known as a “spec” and test filenames include the word “spec”. Well stick with that convention.
:markdown :marked
The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But lets make it more modern with an arrow function: The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But lets make it more modern with an arrow function:
``` ```
it('true is true', () => expect(true).toEqual(true)); it('true is true', () => expect(true).toEqual(true));
@ -97,7 +97,7 @@ figure.image-display
Thats a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next. Thats a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next.
.l-main-section .l-main-section
:markdown :marked
## Prepare for TypeScript ## Prepare for TypeScript
As weve seen before, we first have to tell the compiler how to compile our TypeScript files with As weve seen before, we first have to tell the compiler how to compile our TypeScript files with
@ -125,12 +125,12 @@ pre.prettyprint.lang-bash
code npm run tsc code npm run tsc
.alert.is-helpful .alert.is-helpful
:markdown :marked
Our editor and the compiler may complain that they dont know Our editor and the compiler may complain that they dont know
what `it` and `expect` are because they lack the typing files that describe Jasmine. what `it` and `expect` are because they lack the typing files that describe Jasmine.
We can ignore those annoying complaints for now as they are harmless. We can ignore those annoying complaints for now as they are harmless.
:markdown :marked
If we reload the browser, we should see the same Jasmine test-runner output as before. If we reload the browser, we should see the same Jasmine test-runner output as before.
Well be evolving these tests rapidly and it would be nice to have the browser refresh automatically as we make changes and recompile. Well be evolving these tests rapidly and it would be nice to have the browser refresh automatically as we make changes and recompile.
@ -140,13 +140,13 @@ pre.prettyprint.lang-bash
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm start code npm start
:markdown :marked
Now navigate to `1st-tests.html` Now navigate to `1st-tests.html`
We should get the same Jasmine test-runner output as before. We should get the same Jasmine test-runner output as before.
.l-main-section .l-main-section
:markdown :marked
## Add a describe and another test ## Add a describe and another test
We cant tell what file produced these test results. We only have one file at the moment but soon well write more. We cant tell what file produced these test results. We only have one file at the moment but soon well write more.
@ -166,7 +166,7 @@ pre.prettyprint.lang-bash
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/test-report-1-spec-0-failures.png' style="height:100px;" alt="1 spec, 0 failures") img(src='/resources/images/devguide/jasmine-testing-101/test-report-1-spec-0-failures.png' style="height:100px;" alt="1 spec, 0 failures")
:markdown :marked
Lets add another Jasmine test to `1st.spec.ts` Lets add another Jasmine test to `1st.spec.ts`
``` ```
it('null is not the same thing as undefined', it('null is not the same thing as undefined',
@ -178,23 +178,23 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-0-failures.png' style="height:100px;" alt="refreshed 2 specs, 0 failures") img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-0-failures.png' style="height:100px;" alt="refreshed 2 specs, 0 failures")
:markdown :marked
What does a failing test look like? Remove the `.not`. The browser refreshes and shows: What does a failing test look like? Remove the `.not`. The browser refreshes and shows:
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-1-failure.png' style="height:190px;" alt="failing test 2 specs, 1 failure") img(src='/resources/images/devguide/jasmine-testing-101/test-report-2-specs-1-failure.png' style="height:190px;" alt="failing test 2 specs, 1 failure")
:markdown :marked
Click the `Spec List` link just below “2 specs, 1 failure” to see the summary again: Click the `Spec List` link just below “2 specs, 1 failure” to see the summary again:
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/spec-list-2-specs-1-failure.png' style="height:140px;" alt="2 specs, 1 failure") img(src='/resources/images/devguide/jasmine-testing-101/spec-list-2-specs-1-failure.png' style="height:140px;" alt="2 specs, 1 failure")
:markdown :marked
We can re-run just the failing test by double-clicking it. Try it! We can re-run just the failing test by double-clicking it. Try it!
.l-main-section .l-main-section
:markdown :marked
## Debug the test ## Debug the test
Suppose we didnt know what was going on. We can debug it in the browser. Suppose we didnt know what was going on. We can debug it in the browser.
@ -209,7 +209,7 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/jasmine-testing-101/null-to-equal-undefined.png' style="height:500px;" alt="null === undefined") img(src='/resources/images/devguide/jasmine-testing-101/null-to-equal-undefined.png' style="height:500px;" alt="null === undefined")
:markdown :marked
How about that! They really arent equal. How about that! They really arent equal.
- remove the breakpoint (right-click in the “Breakpoints” section and chose “Remove breakpoint”) - remove the breakpoint (right-click in the “Breakpoints” section and chose “Remove breakpoint”)
- Click the “play” icon to resume the test (or F8) - Click the “play” icon to resume the test (or F8)
@ -222,14 +222,14 @@ figure.image-display
<!-- TODO <!-- TODO
.l-main-section .l-main-section
:markdown :marked
## Learn more ## Learn more
Learn more about basic Jasmine testing here Learn more about basic Jasmine testing here
[Resources TBD](./#) [Resources TBD](./#)
--> -->
.l-main-section .l-main-section
:markdown :marked
## Whats Next? ## Whats Next?
Now that were familiar with Jasmine on its own, were ready to test an application. Now that were familiar with Jasmine on its own, were ready to test an application.

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
Well test an Angular pipe in this chapter Well test an Angular pipe in this chapter
An Angular pipe is a declarative way in HTML to transform some input into some displayable output. An Angular pipe is a declarative way in HTML to transform some input into some displayable output.
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
code-example(format="linenums" language="html" escape="html"). code-example(format="linenums" language="html" escape="html").
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2> <h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
:markdown :marked
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief: The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
``` ```
@ -35,14 +35,14 @@ code-example(format="linenums" language="html" escape="html").
.callout.is-helpful .callout.is-helpful
header Prior Knowledge header Prior Knowledge
:markdown :marked
The Unit Testing chapters build upon each other. We recommend reading them in order. The Unit Testing chapters build upon each other. We recommend reading them in order.
We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools We're also assuming that you're already comfortable with basic Angular 2 concepts and the tools
we introduced in the [QuickStart](../quickstart.html) and we introduced in the [QuickStart](../quickstart.html) and
the [Tour of Heroes](../tutorial/) tutorial the [Tour of Heroes](../tutorial/) tutorial
such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>. such as <code>npm</code>, <code>gulp</code>, and <code>live-server</code>.
:markdown :marked
## Add the Angular library ## Add the Angular library
Looking back at `unit-tests.html` we realize that we have not loaded the Angular library. Looking back at `unit-tests.html` we realize that we have not loaded the Angular library.
Yet we were able to load and test the applications `Hero` class. Yet we were able to load and test the applications `Hero` class.
@ -54,7 +54,7 @@ figure.image-display
img(src='/resources/images/devguide/testing-an-angular-pipe/big-time-fail-screen.png' img(src='/resources/images/devguide/testing-an-angular-pipe/big-time-fail-screen.png'
style="width:400px;" alt="Jasmine's' big time fail screen") style="width:400px;" alt="Jasmine's' big time fail screen")
:markdown :marked
If we then opened the browsers Developer Tools (F12, Ctrl-Shift-I) and looked If we then opened the browsers Developer Tools (F12, Ctrl-Shift-I) and looked
in the console window, we would see that SystemJS in the console window, we would see that SystemJS
tried to load Angular and couldn't find it. tried to load Angular and couldn't find it.
@ -62,7 +62,7 @@ figure.image-display
code-example(format="" language="html" escape="html"). code-example(format="" language="html" escape="html").
GET http://127.0.0.1:8080/src/angular2/angular2 404 (Not Found) GET http://127.0.0.1:8080/src/angular2/angular2 404 (Not Found)
:markdown :marked
We are writing an Angular application afterall and We are writing an Angular application afterall and
we were going to need Angular sooner or later. That time has come. we were going to need Angular sooner or later. That time has come.
The `InitCapsPiep` clearly depends on Angular as is clear in the first few lines: The `InitCapsPiep` clearly depends on Angular as is clear in the first few lines:
@ -147,7 +147,7 @@ figure.image-display
img(src='/resources/images/devguide/testing-an-angular-pipe/5-specs-0-failures.png' img(src='/resources/images/devguide/testing-an-angular-pipe/5-specs-0-failures.png'
style="width:400px;" alt="import promises 5 specs, 0 failures") style="width:400px;" alt="import promises 5 specs, 0 failures")
:markdown :marked
We have a pattern for adding new tests. We have a pattern for adding new tests.
In future, when we add a new spec, we add another `System.import('app/some.spec')` to In future, when we add a new spec, we add another `System.import('app/some.spec')` to

View File

@ -1,6 +1,6 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
:markdown :marked
# Tour of Heroes: the vision # Tour of Heroes: the vision
Our grand plan is to build an app to help a staffing agency manage its stable of heroes. Our grand plan is to build an app to help a staffing agency manage its stable of heroes.
@ -25,7 +25,7 @@ include ../../../../_includes/_util-fns
to chapters with greater depth. to chapters with greater depth.
.l-main-section .l-main-section
:markdown :marked
## The End Game ## The End Game
Here's a visual idea of where we're going in this tour, beginning with the "Dashboard" Here's a visual idea of where we're going in this tour, beginning with the "Dashboard"
@ -34,7 +34,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard") img(src='/resources/images/devguide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard")
:markdown :marked
Above the dashboard are two links ("Dashboard" and "Heroes"). Above the dashboard are two links ("Dashboard" and "Heroes").
We could click them to navigate between this Dashboard and a Heroes view. We could click them to navigate between this Dashboard and a Heroes view.
@ -44,7 +44,7 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/hero-details-1.png' alt="Details of hero in app") img(src='/resources/images/devguide/toh/hero-details-1.png' alt="Details of hero in app")
:markdown :marked
Links at the top can take us to either of the main views. Links at the top can take us to either of the main views.
We'll click the "Back" button which sends us to the "Heroes" master list view with We'll click the "Back" button which sends us to the "Heroes" master list view with
"Magneta" as the selected hero. "Magneta" as the selected hero.
@ -52,7 +52,7 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app") img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app")
:markdown :marked
We click a different hero and the readonly mini-detail beneath the list reflects our new choice. 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 We click the "View Details" button to drill into the
@ -63,14 +63,14 @@ figure.image-display
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations") img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations")
:markdown :marked
Here's our app in action Here's our app in action
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action") img(src='/resources/images/devguide/toh/toh-anim.gif' alt="Tour of Heroes in Action")
.l-main-section .l-main-section
:markdown :marked
## How We Roll ## How We Roll
Well build this Tour of Heroes together, step by step. Well build this Tour of Heroes together, step by step.

View File

@ -1,7 +1,7 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
.l-main-section .l-main-section
:markdown :marked
# Once Upon a Time # Once Upon a Time
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends. Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
@ -22,32 +22,32 @@ include ../../../../_includes/_util-fns
| └── tsconfig.json | └── tsconfig.json
└── package.json └── package.json
:markdown :marked
### Keep the app running ### Keep the app running
Start the TypeScript compiler and have it watch for changes in one terminal window by typing Start the TypeScript compiler and have it watch for changes in one terminal window by typing
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm run tsc code npm run tsc
:markdown :marked
Now open another terminal window and start the server by typing Now open another terminal window and start the server by typing
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm start code npm start
:markdown :marked
This command starts the server, launches the app in a browser, This command starts the server, launches the app in a browser,
and keeps the app running while we continue to build the Tour of Heroes. and keeps the app running while we continue to build the Tour of Heroes.
.l-sub-section .l-sub-section
:markdown :marked
These two steps watch all project files. They recompile TypeScript files and re-run These two steps watch all project files. They recompile TypeScript files and re-run
the app when any file changes. the app when any file changes.
If the watchers fail to detect renamed or new files, If the watchers fail to detect renamed or new files,
stop these commands in each terminal by typing `CTRL+C` and then re-run them. stop these commands in each terminal by typing `CTRL+C` and then re-run them.
.l-main-section .l-main-section
:markdown :marked
## Show our Hero ## Show our Hero
We want to display Hero data in our app We want to display Hero data in our app
@ -61,12 +61,12 @@ include ../../../../_includes/_util-fns
} }
``` ```
:markdown :marked
Now we update the template in the `@Component` decoration with data bindings to these new properties. Now we update the template in the `@Component` decoration with data bindings to these new properties.
code-example(format=""). code-example(format="").
template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero}} details!&lt/h2>' template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero}} details!&lt/h2>'
:markdown :marked
The browser should refresh and display our title and 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. The double curly braces tell our app to read the `title` and `hero` properties from the component and render them.
@ -103,7 +103,7 @@ include ../../../../_includes/_util-fns
code-example(format=""). code-example(format="").
template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero.name}} details!&lt/h2>' template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero.name}} details!&lt/h2>'
:markdown :marked
The browser refreshes and continues to display our heros name. The browser refreshes and continues to display our heros name.
### Adding more HTML ### Adding more HTML
@ -112,7 +112,7 @@ include ../../../../_includes/_util-fns
code-example(format="linenums"). code-example(format="linenums").
template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero.name}} details!&lt/h2>&ltdiv>&ltlabel>id: &lt/label>{{hero.id}}&lt/div>&ltdiv>&ltlabel>name: &lt/label>{{hero.name}}&lt/div>' template: '&lt;h1>{{title}}&lt/h1>&lth2>{{hero.name}} details!&lt/h2>&ltdiv>&ltlabel>id: &lt/label>{{hero.id}}&lt/div>&ltdiv>&ltlabel>name: &lt/label>{{hero.name}}&lt/div>'
:markdown :marked
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. 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 ### Multi-line template strings
@ -136,7 +136,7 @@ include ../../../../_includes/_util-fns
.callout.is-important .callout.is-important
header A back-tick is not a single quote header A back-tick is not a single quote
:markdown :marked
**Be careful!** A back-tick (`) looks a lot like a single quote ('). **Be careful!** A back-tick (`) looks a lot like a single quote (').
It's actually a completely different character. It's actually a completely different character.
Back-ticks can do more than demarcate a string. Back-ticks can do more than demarcate a string.
@ -145,7 +145,7 @@ include ../../../../_includes/_util-fns
is part of a single template string. is part of a single template string.
.l-main-section .l-main-section
:markdown :marked
## Editing Our Hero ## Editing Our Hero
We want to be able to edit the hero name in a textbox. We want to be able to edit the hero name in a textbox.
@ -161,7 +161,7 @@ include ../../../../_includes/_util-fns
&ltdiv>&ltinput value="{{hero.name}}" placeholder="name">&lt/div> &ltdiv>&ltinput value="{{hero.name}}" placeholder="name">&lt/div>
&lt/div> &lt/div>
` `
:markdown :marked
We see in the browser that the heros name does appear in the `<input>` textbox. We see in the browser that the heros name does appear in the `<input>` textbox.
But something doesnt feel right. But something doesnt feel right.
When we change the name, we notice that our change When we change the name, we notice that our change
@ -177,20 +177,20 @@ include ../../../../_includes/_util-fns
Lets update the template to use the **`ng-model`** built-in directive for two-way binding. Lets update the template to use the **`ng-model`** built-in directive for two-way binding.
.l-sub-section .l-sub-section
:markdown :marked
Learn more about `ng-model` in the [Template Syntax](../guide/template-syntax.html#ng-model) Learn more about `ng-model` in the [Template Syntax](../guide/template-syntax.html#ng-model)
:markdown :marked
Replace the `<input>` with the following HTML Replace the `<input>` with the following HTML
code-example(language="html"). code-example(language="html").
&lt;input [(ng-model)]="hero.name" placeholder="name"> &lt;input [(ng-model)]="hero.name" placeholder="name">
:markdown :marked
Unfortunately, that change broke our application and we're no longer displaying the hero in the browser. Unfortunately, that change broke our application and we're no longer displaying the hero in the browser.
Lets fix that next. Lets fix that next.
.l-main-section .l-main-section
:markdown :marked
## Declaring Template Directives ## Declaring Template Directives
We added the `ng-model` directive but we didn't tell Angular about it. We added the `ng-model` directive but we didn't tell Angular about it.
@ -218,7 +218,7 @@ include ../../../../_includes/_util-fns
code-example(language="html"). code-example(language="html").
EXCEPTION: No value accessor for ' ' in [null] EXCEPTION: No value accessor for ' ' in [null]
:markdown :marked
Apparently declaring the `NgModel` is not quite enough. Apparently declaring the `NgModel` is not quite enough.
## Declare Multiple Form Directives ## Declare Multiple Form Directives
@ -234,9 +234,9 @@ include ../../../../_includes/_util-fns
bundled in a convenient array called `FORM_DIRECTIVES`. bundled in a convenient array called `FORM_DIRECTIVES`.
<!-- TODO <!-- TODO
.alert.is-helpful .alert.is-helpful
:markdown :marked
Learn more about Angular Forms in the [Forms chapter]() Learn more about Angular Forms in the [Forms chapter]()
:markdown :marked
--> -->
Lets forget about importing `NgModel` and import the `FORM_DIRECTIVES` array instead: Lets forget about importing `NgModel` and import the `FORM_DIRECTIVES` array instead:
``` ```
@ -259,7 +259,7 @@ include ../../../../_includes/_util-fns
and plug that array into the `directives` property. and plug that array into the `directives` property.
.l-main-section .l-main-section
:markdown :marked
## The Road Weve Travelled ## The Road Weve Travelled
Lets take stock of what weve built. Lets take stock of what weve built.
@ -306,7 +306,7 @@ include ../../../../_includes/_util-fns
bootstrap(AppComponent); bootstrap(AppComponent);
.l-main-section .l-main-section
:markdown :marked
## The Road Ahead ## The Road Ahead
Our Tour of Heroes only displays one hero and we really want to display a list of heroes. 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 also want to allow the user to select a hero and display their details.

View File

@ -1,7 +1,7 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
.l-main-section .l-main-section
:markdown :marked
# It Takes Many Heroes # It Takes Many Heroes
Our story needs more heroes. Our story needs more heroes.
Well expand our Tour of Heroes app to display a list of heroes, Well expand our Tour of Heroes app to display a list of heroes,
@ -12,7 +12,7 @@ include ../../../../_includes/_util-fns
so well need a way to do that. so well need a way to do that.
.l-main-section .l-main-section
:markdown :marked
## Where We Left Off ## Where We Left Off
Before we continue with Part 2 of the Tour of Heroes, Before we continue with Part 2 of the Tour of Heroes,
lets verify we have the following structure after [Part 1](./toh-pt1.html). lets verify we have the following structure after [Part 1](./toh-pt1.html).
@ -27,24 +27,24 @@ include ../../../../_includes/_util-fns
| ├── index.html | ├── index.html
| └── tsconfig.json | └── tsconfig.json
└── package.json └── package.json
:markdown :marked
### Keep the app running ### Keep the app running
Start the TypeScript compiler and have it watch for changes in one terminal window by typing Start the TypeScript compiler and have it watch for changes in one terminal window by typing
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm run tsc code npm run tsc
:markdown :marked
Now open another terminal window and start the server by typing Now open another terminal window and start the server by typing
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code npm start code npm start
:markdown :marked
This will keep the application running while we continue to build the Tour of Heroes. This will keep the application running while we continue to build the Tour of Heroes.
.l-main-section .l-main-section
:markdown :marked
## Displaying Our Heroes ## Displaying Our Heroes
### Creating heroes ### Creating heroes
Lets create an array of ten heroes at the bottom of `app.ts`. Lets create an array of ten heroes at the bottom of `app.ts`.
@ -74,12 +74,12 @@ include ../../../../_includes/_util-fns
``` ```
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array. We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
.l-sub-section .l-sub-section
:markdown :marked
We could have defined the heroes list here in this component class. We could have defined the heroes list here in this component class.
But we know that well get the heroes from a data service. But we know that well get the heroes from a data service.
Because we know where we are heading, it makes sense to separate the hero data Because we know where we are heading, it makes sense to separate the hero data
from the class implementation from the start. from the class implementation from the start.
:markdown :marked
### Displaying heroes in a template ### Displaying heroes in a template
Our component has`heroes`. Lets create an unordered list in our template to display them. Our component has`heroes`. Lets create an unordered list in our template to display them.
Well insert the following chunk of HTML below the title and above the hero details. Well insert the following chunk of HTML below the title and above the hero details.
@ -104,11 +104,11 @@ include ../../../../_includes/_util-fns
<li *ng-for="#hero of heroes"> <li *ng-for="#hero of heroes">
``` ```
.alert.is-critical .alert.is-critical
:markdown :marked
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax. The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax.
.l-sub-section .l-sub-section
:markdown :marked
The (`*`) prefix to `ng-for` indicates that the `<li>` element and its children The (`*`) prefix to `ng-for` indicates that the `<li>` element and its children
constitute a master template. constitute a master template.
@ -125,7 +125,7 @@ include ../../../../_includes/_util-fns
Learn more about `ng-for` and local template variables in the Learn more about `ng-for` and local template variables in the
[Template Syntax](../guide/template-syntax.html#ng-for) chapter. [Template Syntax](../guide/template-syntax.html#ng-for) chapter.
:markdown :marked
With this background in mind, we now insert some content between the `<li>` tags With this background in mind, we now insert some content between the `<li>` tags
that uses the `hero` template variable to display the heros properties. that uses the `hero` template variable to display the heros properties.
@ -134,7 +134,7 @@ include ../../../../_includes/_util-fns
&lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}} &lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}}
&lt;/li> &lt;/li>
:markdown :marked
### Declaring ng-for ### Declaring ng-for
When we view the running app in the browser we see nothing … no heroes. When we view the running app in the browser we see nothing … no heroes.
We open the developer tools and see an error in the console. We open the developer tools and see an error in the console.
@ -144,7 +144,7 @@ include ../../../../_includes/_util-fns
Can't bind to 'ngForOf' since it isn't a known property of the '&lt;template>' element and Can't bind to 'ngForOf' since it isn't a known property of the '&lt;template>' element and
there are no matching directives with a corresponding property there are no matching directives with a corresponding property
:markdown :marked
Thankfully we have a clear error message that indicates where we went wrong. Thankfully we have a clear error message that indicates where we went wrong.
We used `ng-for` in the template but we didnt tell the component about it. We used `ng-for` in the template but we didnt tell the component about it.
From Angular's perspective, `ng-for` is a meaningless attribute. From Angular's perspective, `ng-for` is a meaningless attribute.
@ -200,14 +200,14 @@ include ../../../../_includes/_util-fns
&lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}} &lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}}
&lt;/li> &lt;/li>
&lt;/ul> &lt;/ul>
:markdown :marked
Our styled list of heroes should look like this: Our styled list of heroes should look like this:
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app (no selection color)") img(src='/resources/images/devguide/toh/heroes-list-2.png' alt="Output of heroes list app (no selection color)")
.l-main-section .l-main-section
:markdown :marked
## Selecting a Hero ## Selecting a Hero
We have a list of heroes and we have a single hero displayed in our app. 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. The list and the single hero are not connected in any way.
@ -224,19 +224,19 @@ include ../../../../_includes/_util-fns
&lt;li *ng-for="#hero of heroes" (click)="onSelect(hero)"> &lt;li *ng-for="#hero of heroes" (click)="onSelect(hero)">
&lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}} &lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}}
&lt;/li> &lt;/li>
:markdown :marked
Focus on the event binding Focus on the event binding
pre.prettyprint.lang-bash pre.prettyprint.lang-bash
code (click)="onSelect(hero)"> code (click)="onSelect(hero)">
:markdown :marked
The parenthesis identify the `<li>` elements `click` event as the target. The parenthesis identify the `<li>` elements `click` event as the target.
The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`, The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`,
passing the local template variable `hero` as an argument. passing the local template variable `hero` as an argument.
Thats the same `hero` variable we defined previously in the `ng-for`. Thats the same `hero` variable we defined previously in the `ng-for`.
.l-sub-section .l-sub-section
:markdown :marked
Learn more about Event Binding in the [Templating Syntax](../guide/template-syntax.html#event-binding) chapter. Learn more about Event Binding in the [Templating Syntax](../guide/template-syntax.html#event-binding) chapter.
:markdown :marked
### Add the click handler ### Add the click handler
Our event binding refers to an `onSelect` method that doesnt exist yet. Our event binding refers to an `onSelect` method that doesnt exist yet.
Well add that method to our component now. Well add that method to our component now.
@ -271,7 +271,7 @@ include ../../../../_includes/_util-fns
&lt;input [(ng-model)]="selectedHero.name" placeholder="name">&lt;/input> &lt;input [(ng-model)]="selectedHero.name" placeholder="name">&lt;/input>
&lt;/div> &lt;/div>
:markdown :marked
### Hide the empty detail with ng-if ### Hide the empty detail with ng-if
When our app loads we see a list of heroes, but a hero is not selected. When our app loads we see a list of heroes, but a hero is not selected.
@ -281,7 +281,7 @@ include ../../../../_includes/_util-fns
code-example(language="html"). code-example(language="html").
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null] EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
:markdown :marked
Remember that we are displaying `selectedHero.name` in the template. Remember that we are displaying `selectedHero.name` in the template.
This name property does not exist because `selectedHero`itself is undefined. This name property does not exist because `selectedHero`itself is undefined.
@ -300,17 +300,17 @@ include ../../../../_includes/_util-fns
&lt;/div> &lt;/div>
&lt;/div> &lt;/div>
.alert.is-critical .alert.is-critical
:markdown :marked
Remember that the leading asterisk (`*`) in front of `ng-if` is Remember that the leading asterisk (`*`) in front of `ng-if` is
a critical part of this syntax. a critical part of this syntax.
:markdown :marked
When there is no `selectedHero`, the `ng-if` directive removes the hero detail HTML from the DOM. When there is no `selectedHero`, the `ng-if` directive removes the hero detail HTML from the DOM.
There will be no hero detail elements and no bindings to worry about. There will be no hero detail elements and no bindings to worry about.
When the user picks a hero, `selectedHero` becomes "truthy" and When the user picks a hero, `selectedHero` becomes "truthy" and
`ng-if` puts the hero detail content into the DOM and evaluates the nested bindings. `ng-if` puts the hero detail content into the DOM and evaluates the nested bindings.
.l-sub-section .l-sub-section
:markdown :marked
`ng-if` and `ng-for` are called “structural directives” because they can change the `ng-if` and `ng-for` are called “structural directives” because they can change the
structure of portions of the DOM. structure of portions of the DOM.
In other words, they give structure to the way Angular displays content in the DOM. In other words, they give structure to the way Angular displays content in the DOM.
@ -318,7 +318,7 @@ include ../../../../_includes/_util-fns
Learn more about `ng-if`, `ng-for` and other structural directives in the Learn more about `ng-if`, `ng-for` and other structural directives in the
[Template Syntax](../guide/template-syntax.html#directives) chapter [Template Syntax](../guide/template-syntax.html#directives) chapter
:markdown :marked
We learned previously with `NgFor` that we must declare every directive we use in the components `@Component` decorator. We learned previously with `NgFor` that we must declare every directive we use in the components `@Component` decorator.
Lets do that again for `NgIf`. Lets do that again for `NgIf`.
@ -327,7 +327,7 @@ include ../../../../_includes/_util-fns
``` ```
import {bootstrap, Component, FORM_DIRECTIVES, NgFor, NgIf} from 'angular2/angular2'; import {bootstrap, Component, FORM_DIRECTIVES, NgFor, NgIf} from 'angular2/angular2';
``` ```
:markdown :marked
Now add `NgIf` to the directives array in the `@Component` decorator: Now add `NgIf` to the directives array in the `@Component` decorator:
``` ```
directives: [FORM_DIRECTIVES, NgFor, NgIf] directives: [FORM_DIRECTIVES, NgFor, NgIf]
@ -346,7 +346,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="Selected hero") img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="Selected hero")
:markdown :marked
First well add a `getSelectedClass` method to the component that compares the current `selectedHero` to a hero parameter First well add a `getSelectedClass` method to the component that compares the current `selectedHero` to a hero parameter
and returns an object with a single key/value pair. and returns an object with a single key/value pair.
@ -371,17 +371,17 @@ include ../../../../_includes/_util-fns
&lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}} &lt;span class="badge">{{hero.id}}&lt;/span> {{hero.name}}
&lt;/li> &lt;/li>
:markdown :marked
Notice in the template that the `ng-class` name is surrounded in square brackets (`[]`). Notice in the template that the `ng-class` name is surrounded in square brackets (`[]`).
This is the syntax for a Property Binding, a binding in which data flows one way This is the syntax for a Property Binding, a binding in which data flows one way
from the data source (the `getSelectedClass`) to a property of the `ng-class` directive. from the data source (the `getSelectedClass`) to a property of the `ng-class` directive.
.l-sub-section .l-sub-section
:markdown :marked
Learn more about [ng-class](../guide/template-syntax.html#ng-class) Learn more about [ng-class](../guide/template-syntax.html#ng-class)
and [Property Binding](../guide/template-syntax.html#property-binding) and [Property Binding](../guide/template-syntax.html#property-binding)
in the Template Syntax chapter in the Template Syntax chapter
:markdown :marked
We've added yet another new directive to our template that we have to import and declare We've added yet another new directive to our template that we have to import and declare
in the components `directives` array as weve done twice before. in the components `directives` array as weve done twice before.
``` ```
@ -398,7 +398,7 @@ include ../../../../_includes/_util-fns
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app") img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="Output of heroes list app")
:markdown :marked
We select a different hero and the tell-tale color switches to that hero. We select a different hero and the tell-tale color switches to that hero.
## Declaring Built-In Directives ## Declaring Built-In Directives
@ -427,7 +427,7 @@ include ../../../../_includes/_util-fns
Cleaner code for the win! Cleaner code for the win!
.l-main-section .l-main-section
:markdown :marked
## The Road Weve Travelled ## The Road Weve Travelled
Heres what we achieved in this chapter: Heres what we achieved in this chapter:
@ -439,4 +439,3 @@ include ../../../../_includes/_util-fns
Our Tour of Heroes has grown, but its far from complete. Our Tour of Heroes has grown, but its far from complete.
We want to get data from an asynchronous source using promises, use shared services, and create reusable components. We want to get data from an asynchronous source using promises, use shared services, and create reusable components.
Well learn more about these tasks in the coming tutorial chapters. Well learn more about these tasks in the coming tutorial chapters.

View File

@ -22,14 +22,14 @@ module.exports = function(encodeCodeBlock) {
newLines.pop(); newLines.pop();
} else { } else {
// wierd case - first expression in str is an @example // wierd case - first expression in str is an @example
// in this case the :markdown appear above the str passed in, // in this case the :marked appear above the str passed in,
// so we need to put 'something' into the markdown tag. // so we need to put 'something' into the markdown tag.
newLines.push(sp + "."); // '.' is a dummy char newLines.push(sp + "."); // '.' is a dummy char
} }
} }
newLines.push(spMixin + line); newLines.push(spMixin + line);
// after a mixin line we need to reenter markdown. // after a mixin line we need to reenter markdown.
newLines.push(spMixin + ':markdown'); newLines.push(spMixin + ':marked');
isAfterMarkdownTag = true; isAfterMarkdownTag = true;
} else { } else {
if ((!isAfterMarkdownTag) || (line.trim().length > 0)) { if ((!isAfterMarkdownTag) || (line.trim().length > 0)) {

View File

@ -14,7 +14,7 @@ p.location-badge.
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} } exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
defined in {$ githubViewLink(doc) $} defined in {$ githubViewLink(doc) $}
:markdown :marked
{%- if doc.notYetDocumented %} {%- if doc.notYetDocumented %}
*Not Yet Documented* *Not Yet Documented*
{% else %} {% else %}
@ -43,7 +43,7 @@ p.location-badge.
pre.prettyprint pre.prettyprint
code. code.
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.parameters) | indent(8, false) | trim $} {$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.parameters) | indent(8, false) | trim $}
:markdown :marked
{$ doc.constructorDoc.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $} {$ doc.constructorDoc.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
{% endif -%} {% endif -%}
@ -54,7 +54,7 @@ p.location-badge.
code. code.
{$ member.name $}{$ paramList(member.parameters) | indent(8, false) | trim $}{$ returnType(member.returnType) $} {$ member.name $}{$ paramList(member.parameters) | indent(8, false) | trim $}{$ returnType(member.returnType) $}
:markdown :marked
{$ member.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $} {$ member.description | indentForMarkdown(6) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
{% endif %}{% endfor %} {% endif %}{% endfor %}

View File

@ -17,7 +17,7 @@
code {$ property.bindingName | dashCase $} code {$ property.bindingName | dashCase $}
| &nbsp;bound to&nbsp; | &nbsp;bound to&nbsp;
code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $} code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $}
:markdown :marked
{$ property.memberDoc.description | indentForMarkdown(2) | trimBlankLines $}{% endfor %} {$ property.memberDoc.description | indentForMarkdown(2) | trimBlankLines $}{% endfor %}
{% endif %} {% endif %}
@ -29,7 +29,7 @@
code {$ property.bindingName | dashCase $} code {$ property.bindingName | dashCase $}
| &nbsp;bound to&nbsp; | &nbsp;bound to&nbsp;
code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $} code {$ property.memberDoc.classDoc.name $}.{$ property.propertyName $}
:markdown :marked
{$ event.memberDoc.description | indentForMarkdown(2) | trimBlankLines $} {$ event.memberDoc.description | indentForMarkdown(2) | trimBlankLines $}
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@ -14,7 +14,7 @@ include ../../_util-fns
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} } exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
defined in {$ githubViewLink(doc) $} defined in {$ githubViewLink(doc) $}
:markdown :marked
{$ doc.description | indentForMarkdown(4) | trimBlankLines $} {$ doc.description | indentForMarkdown(4) | trimBlankLines $}
{% endblock %} {% endblock %}

View File

@ -14,7 +14,7 @@ include ../../_util-fns
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} } exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
defined in {$ githubViewLink(doc) $} defined in {$ githubViewLink(doc) $}
:markdown :marked
{%- if doc.notYetDocumented %} {%- if doc.notYetDocumented %}
### *Not Yet Documented* ### *Not Yet Documented*
{% else %} {% else %}

View File

@ -49,7 +49,7 @@ module.exports = function convertBackticksToCodeBlocks() {
// modulo op in next line insures that pad is always a multiple of 2 ( jade whitespace). // modulo op in next line insures that pad is always a multiple of 2 ( jade whitespace).
postPad = postPad.substr(2 + (postPad.length % 2)); // exdent postPad = postPad.substr(2 + (postPad.length % 2)); // exdent
} }
replaceVal = replaceVal + postPad + ':markdown\n'; replaceVal = replaceVal + postPad + ':marked\n';
} }
doc.renderedContent = doc.renderedContent.replace(entireBlock, replaceVal); doc.renderedContent = doc.renderedContent.replace(entireBlock, replaceVal);
captures = BACKTICK_CAPTURE.exec(doc.renderedContent); captures = BACKTICK_CAPTURE.exec(doc.renderedContent);

View File

@ -30,7 +30,7 @@ describe('convertBackticksToCodeBlocks', function() {
'export class TypeScriptClass {\n' + 'export class TypeScriptClass {\n' +
'}\n' + '}\n' +
'\n' + '\n' +
':markdown\n' + ':marked\n' +
'postamble\n' 'postamble\n'
); );
}); });

View File

@ -1,7 +1,7 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
.l-main-section .l-main-section
:markdown :marked
## Install Angular2 ## Install Angular2
There are four steps to create any Angular app: There are four steps to create any Angular app:
@ -19,14 +19,14 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Typescript vs ES5 header Typescript vs ES5
:markdown :marked
Although we work through the examples in TypeScript, you can also use Although we work through the examples in TypeScript, you can also use
regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript
version. Note that in ES5, you'd want to name your files `.js` rather than version. Note that in ES5, you'd want to name your files `.js` rather than
`.ts`. `.ts`.
.l-main-section .l-main-section
:markdown :marked
## Create an entry point ## Create an entry point
Create an `index.html` file and add the Angular library tags and a `main.ts` file where Create an `index.html` file and add the Angular library tags and a `main.ts` file where
you'll build your first component. you'll build your first component.
@ -40,12 +40,12 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Don't use code.angularjs.org in a live app header Don't use code.angularjs.org in a live app
:markdown :marked
This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is
fine for examples, but you'd want to serve it yourself or use a CDN for real deployment. fine for examples, but you'd want to serve it yourself or use a CDN for real deployment.
.l-main-section .l-main-section
:markdown :marked
## Set up the starting component ## Set up the starting component
In `main.ts`, create a class called `AppComponent`, configure it to bind to the In `main.ts`, create a class called `AppComponent`, configure it to bind to the
@ -56,14 +56,14 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Annotations vs Decorators header Annotations vs Decorators
:markdown :marked
If you are transpiling using a tool that translates the `@` symbols to If you are transpiling using a tool that translates the `@` symbols to
annotations (for example Traceur), you will need to import the annotation versions of annotations (for example Traceur), you will need to import the annotation versions of
Component and View. That can be easily achieved using Component and View. That can be easily achieved using
`import {ComponentAnnotation as Component, ViewAnnotation as View}`. `import {ComponentAnnotation as Component, ViewAnnotation as View}`.
.l-main-section .l-main-section
:markdown :marked
## Run it! ## Run it!
Open `index.html` through your web server and you should see: Open `index.html` through your web server and you should see:
@ -72,13 +72,13 @@ include ../../../../_includes/_util-fns
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App") img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
.l-main-section .l-main-section
:markdown :marked
## Explanations ## Explanations
This basic Angular app contains the structure for any app you'll build. This basic Angular app contains the structure for any app you'll build.
.l-sub-section .l-sub-section
:markdown :marked
### It's all a tree ### It's all a tree
You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top
@ -94,7 +94,7 @@ include ../../../../_includes/_util-fns
these in the following pages. these in the following pages.
.l-sub-section .l-sub-section
:markdown :marked
### @Component and @View annotations ### @Component and @View annotations
A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`). A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`).
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file. The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file.
.l-sub-section .l-sub-section
:markdown :marked
### import vs. window.angular ### import vs. window.angular
The main difference between the ES5 and TypeScript versions is the loading of modules. The main difference between the ES5 and TypeScript versions is the loading of modules.

View File

@ -1,7 +1,7 @@
include ../../../../_includes/_util-fns include ../../../../_includes/_util-fns
.l-main-section .l-main-section
:markdown :marked
## Install Angular2 ## Install Angular2
There are four steps to create any Angular app: There are four steps to create any Angular app:
@ -19,14 +19,14 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Typescript vs ES5 header Typescript vs ES5
:markdown :marked
Although we work through the examples in TypeScript, you can also use Although we work through the examples in TypeScript, you can also use
regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript regular ES5. Click the ES5 link in any code box to see the ES5 JavaScript
version. Note that in ES5, you'd want to name your files `.js` rather than version. Note that in ES5, you'd want to name your files `.js` rather than
`.ts`. `.ts`.
.l-main-section .l-main-section
:markdown :marked
## Create an entry point ## Create an entry point
Create an `index.html` file and add the Angular library tags and a `main.ts` file where Create an `index.html` file and add the Angular library tags and a `main.ts` file where
you'll build your first component. you'll build your first component.
@ -40,12 +40,12 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Don't use code.angularjs.org in a live app header Don't use code.angularjs.org in a live app
:markdown :marked
This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is This example serves the Angular library from <a href="http://code.angularjs.org">code.angularjs.org</a>. This is
fine for examples, but you'd want to serve it yourself or use a CDN for real deployment. fine for examples, but you'd want to serve it yourself or use a CDN for real deployment.
.l-main-section .l-main-section
:markdown :marked
## Set up the starting component ## Set up the starting component
In `main.ts`, create a class called `AppComponent`, configure it to bind to the In `main.ts`, create a class called `AppComponent`, configure it to bind to the
@ -56,14 +56,14 @@ include ../../../../_includes/_util-fns
.callout.is-helpful .callout.is-helpful
header Annotations vs Decorators header Annotations vs Decorators
:markdown :marked
If you are transpiling using a tool that translates the `@` symbols to If you are transpiling using a tool that translates the `@` symbols to
annotations (for example Traceur), you will need to import the annotation versions of annotations (for example Traceur), you will need to import the annotation versions of
Component and View. That can be easily achieved using Component and View. That can be easily achieved using
`import {ComponentAnnotation as Component, ViewAnnotation as View}`. `import {ComponentAnnotation as Component, ViewAnnotation as View}`.
.l-main-section .l-main-section
:markdown :marked
## Run it! ## Run it!
Open `index.html` through your web server and you should see: Open `index.html` through your web server and you should see:
@ -72,13 +72,13 @@ include ../../../../_includes/_util-fns
img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App") img(src='/resources/images/examples/setup-example1.png' alt="Example of Todo App")
.l-main-section .l-main-section
:markdown :marked
## Explanations ## Explanations
This basic Angular app contains the structure for any app you'll build. This basic Angular app contains the structure for any app you'll build.
.l-sub-section .l-sub-section
:markdown :marked
### It's all a tree ### It's all a tree
You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top You can think of Angular apps as a tree of components. This root component we've been talking about acts as the top
@ -94,7 +94,7 @@ include ../../../../_includes/_util-fns
these in the following pages. these in the following pages.
.l-sub-section .l-sub-section
:markdown :marked
### @Component and @View annotations ### @Component and @View annotations
A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`). A component annotation describes details about the component. An annotation can be identified by its at-sign (`@`).
@ -104,7 +104,7 @@ include ../../../../_includes/_util-fns
The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file. The `@View` annotation defines the HTML that represents the component. The component you wrote uses an inline template, but you can also have an external template. To use an external template, specify a <code>templateUrl</code> property and give it the path to the HTML file.
.l-sub-section .l-sub-section
:markdown :marked
### import vs. window.angular ### import vs. window.angular
The main difference between the ES5 and TypeScript versions is the loading of modules. The main difference between the ES5 and TypeScript versions is the loading of modules.