(docs) testing and toh formatting improvements
This commit is contained in:
parent
cdec7d1605
commit
93a646d63f
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
// #docregion class-w-annotations
|
// #docregion class-w-annotations
|
||||||
var AppComponent = ng
|
var AppComponent = ng
|
||||||
ng.Component({
|
.Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: '<h1>My First Angular 2 App</h1>'
|
template: '<h1>My First Angular 2 App</h1>'
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<!-- #docregion -->
|
<!-- #docregion -->
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<title>Angular 2 QuickStart</title>
|
||||||
<script src="node_modules/angular2/bundles/angular2.sfx.dev.js"></script>
|
<script src="node_modules/angular2/bundles/angular2.sfx.dev.js"></script>
|
||||||
<script src="app.js"></script>
|
<script src="app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Getting Started</title>
|
<title>Angular 2 QuickStart</title>
|
||||||
<script src="https://code.angularjs.org/tools/system.js"></script>
|
<script src="https://code.angularjs.org/tools/system.js"></script>
|
||||||
<script src="https://code.angularjs.org/tools/typescript.js"></script>
|
<script src="https://code.angularjs.org/tools/typescript.js"></script>
|
||||||
<script src="https://code.angularjs.org/2.0.0-alpha.42/angular2.dev.js"></script>
|
<script src="https://code.angularjs.org/2.0.0-alpha.42/angular2.dev.js"></script>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Getting Started</title>
|
<title>Angular 2 QuickStart</title>
|
||||||
<!-- #docregion libraries -->
|
<!-- #docregion libraries -->
|
||||||
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
<script src="../node_modules/systemjs/dist/system.src.js"></script>
|
||||||
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
|
||||||
|
|
|
@ -2,22 +2,27 @@
|
||||||
"_listtype": "ordered",
|
"_listtype": "ordered",
|
||||||
|
|
||||||
"index": {
|
"index": {
|
||||||
"title": "Testing Guides"
|
"title": "Testing Guides",
|
||||||
|
"intro": "Techniques and practices for testing an Angular 2 app"
|
||||||
},
|
},
|
||||||
|
|
||||||
"jasmine-testing-101": {
|
"jasmine-testing-101": {
|
||||||
"title": "Jasmine Testing 101"
|
"title": "Jasmine Testing 101",
|
||||||
|
"intro": "The basics of testing anything with Jasmine"
|
||||||
},
|
},
|
||||||
|
|
||||||
"application-under-test": {
|
"application-under-test": {
|
||||||
"title": "The Application Under Test"
|
"title": "The Application Under Test",
|
||||||
|
"intro": "A quick look at the application we will test"
|
||||||
},
|
},
|
||||||
|
|
||||||
"first-app-tests": {
|
"first-app-tests": {
|
||||||
"title": "First App Tests"
|
"title": "First App Tests",
|
||||||
|
"intro": "The first test of a simple, non-Angular part of our app"
|
||||||
},
|
},
|
||||||
|
|
||||||
"testing-an-angular-pipe": {
|
"testing-an-angular-pipe": {
|
||||||
"title": "Testing an Angular Pipe"
|
"title": "Testing an Angular Pipe",
|
||||||
|
"intro": "We test an Angular-aware part of our app"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,5 +32,7 @@ figure.image-display
|
||||||
|
|
||||||
We’ll examine the implementation details as we evolve our tests.
|
We’ll examine the implementation details as we evolve our tests.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## What’s Next?
|
## What’s Next?
|
||||||
Now that we’re familiar with how the test app works, we’re ready to poke at it with our first application tests written in Jasmine.
|
Now that we’re familiar with how the test app works, we’re ready to poke at it with our first application tests written in Jasmine.
|
||||||
|
|
|
@ -16,6 +16,8 @@ include ../../../../_includes/_util-fns
|
||||||
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>.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
## Create the test-runner HTML
|
## Create the test-runner HTML
|
||||||
|
|
||||||
|
@ -44,6 +46,8 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
We’re picking up right where we left off. All we’ve done is change the title.
|
We’re picking up right where we left off. All we’ve done is change the title.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## Update `package.json` for testing
|
## Update `package.json` for testing
|
||||||
|
|
||||||
We’ll assume that the application has `package.json` file that looks more or less like
|
We’ll assume that the application has `package.json` file that looks more or less like
|
||||||
|
@ -66,6 +70,8 @@ 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
|
||||||
|
:markdown
|
||||||
## 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:
|
||||||
|
@ -128,6 +134,8 @@ 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
|
||||||
|
:markdown
|
||||||
## 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`
|
||||||
|
@ -139,6 +147,8 @@ pre.prettyprint.lang-bash
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/first-app-tests/passed-2-specs-0-failures.png' style="width:400px;" alt="Two passing tests")
|
img(src='/resources/images/devguide/first-app-tests/passed-2-specs-0-failures.png' style="width:400px;" alt="Two passing tests")
|
||||||
|
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
## Critique
|
## Critique
|
||||||
|
|
||||||
|
@ -150,6 +160,8 @@ figure.image-display
|
||||||
|
|
||||||
We need to relocate these tests to a separate file. Let’s do that next.
|
We need to relocate these tests to a separate file. Let’s do that next.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## 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.
|
||||||
|
@ -165,6 +177,8 @@ figure.image-display
|
||||||
|
|
||||||
You may put your tests elsewhere if you wish. We’re putting ours inside the app, next to the source files that they test.
|
You may put your tests elsewhere if you wish. We’re putting ours inside the app, next to the source files that they test.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## 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`.
|
||||||
|
@ -209,7 +223,7 @@ figure.image-display
|
||||||
<script src="app/hero.js"></script>
|
<script src="app/hero.js"></script>
|
||||||
<script src="app/hero.spec.js"></script>
|
<script src="app/hero.spec.js"></script>
|
||||||
|
|
||||||
## Run and Fail
|
### Run and Fail
|
||||||
|
|
||||||
Look over at the browser (live-server will have reloaded it). The browser displays
|
Look over at the browser (live-server will have reloaded it). The browser displays
|
||||||
|
|
||||||
|
@ -220,10 +234,12 @@ figure.image-display
|
||||||
That’s Jasmine saying “**things are _so_ bad that _I’m not running any tests_.**”
|
That’s Jasmine saying “**things are _so_ bad that _I’m not running any tests_.**”
|
||||||
|
|
||||||
Open the browser’s Developer Tools (F12, Ctrl-Shift-i). There’s an error:
|
Open the browser’s Developer Tools (F12, Ctrl-Shift-i). There’s an error:
|
||||||
```
|
|
||||||
|
code-example(format="" language="html").
|
||||||
Uncaught ReferenceError: exports is not defined
|
Uncaught ReferenceError: exports is not defined
|
||||||
```
|
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## 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`.
|
||||||
|
@ -278,6 +294,8 @@ figure.image-display
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/first-app-tests/test-passed-once-again.png' style="width:400px;" alt="Tests passed once again")
|
img(src='/resources/images/devguide/first-app-tests/test-passed-once-again.png' style="width:400px;" alt="Tests passed once again")
|
||||||
|
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
## Observations
|
## Observations
|
||||||
|
|
||||||
|
@ -307,6 +325,8 @@ figure.image-display
|
||||||
So we must wait until the import completes and only then call the window `onLoad` handler.
|
So we must wait until the import completes and only then call the window `onLoad` handler.
|
||||||
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
|
||||||
|
:markdown
|
||||||
## What’s Next?
|
## What’s 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.
|
||||||
|
|
|
@ -36,7 +36,6 @@ pre.prettyprint.lang-bash
|
||||||
:markdown
|
:markdown
|
||||||
The browser is nice during development of a few tests. It’s not the best venue for working with a lot of tests and it won’t do at all for build automation. We’ll 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. It’s not the best venue for working with a lot of tests and it won’t do at all for build automation. We’ll switch to the karma test-runner when the time comes. But the browser will do for now.
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
:markdown
|
:markdown
|
||||||
Create a new file called`unit-tests.html` and enter the following:
|
Create a new file called`unit-tests.html` and enter the following:
|
||||||
```
|
```
|
||||||
|
@ -73,7 +72,9 @@ figure.image-display
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
It doesn’t get much simpler than that!
|
It doesn’t get much simpler than that!
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## First TypeScript Test
|
## First TypeScript Test
|
||||||
Perhaps too simple. We won’t write our entire test suite inside one HTML file.
|
Perhaps too simple. We won’t write our entire test suite inside one HTML file.
|
||||||
Let’s **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
|
Let’s **extract** that line of test code to a **new file in `src` called `1st.spec.ts` ** .
|
||||||
|
@ -82,7 +83,6 @@ figure.image-display
|
||||||
:markdown
|
:markdown
|
||||||
Among Jasmine developers, a test is known as a “spec” and test filenames include the word “spec”. We’ll stick with that convention.
|
Among Jasmine developers, a test is known as a “spec” and test filenames include the word “spec”. We’ll stick with that convention.
|
||||||
|
|
||||||
.l-main-section
|
|
||||||
:markdown
|
:markdown
|
||||||
The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But let’s make it more modern with an arrow function:
|
The test we wrote is valid TypeScript because any JavaScript is valid TypeScript. But let’s make it more modern with an arrow function:
|
||||||
```
|
```
|
||||||
|
@ -96,6 +96,8 @@ figure.image-display
|
||||||
|
|
||||||
That’s a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next.
|
That’s a reminder that we need to compile our TypeScript test files as we do our TypeScript application files. Do that next.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## Prepare for TypeScript
|
## Prepare for TypeScript
|
||||||
|
|
||||||
As we’ve seen before, we first have to tell the compiler how to compile our TypeScript files with
|
As we’ve seen before, we first have to tell the compiler how to compile our TypeScript files with
|
||||||
|
@ -143,6 +145,8 @@ pre.prettyprint.lang-bash
|
||||||
|
|
||||||
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
|
||||||
|
:markdown
|
||||||
## Add a describe and another test
|
## Add a describe and another test
|
||||||
|
|
||||||
We can’t tell what file produced these test results. We only have one file at the moment but soon we’ll write more.
|
We can’t tell what file produced these test results. We only have one file at the moment but soon we’ll write more.
|
||||||
|
@ -189,6 +193,8 @@ figure.image-display
|
||||||
:markdown
|
:markdown
|
||||||
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
|
||||||
|
:markdown
|
||||||
## Debug the test
|
## Debug the test
|
||||||
Suppose we didn’t know what was going on. We can debug it in the browser.
|
Suppose we didn’t know what was going on. We can debug it in the browser.
|
||||||
|
|
||||||
|
@ -214,10 +220,14 @@ figure.image-display
|
||||||
|
|
||||||
Congratulations … you’ve completed Jasmine testing 101.
|
Congratulations … you’ve completed Jasmine testing 101.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## 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
|
||||||
|
:markdown
|
||||||
## What’s Next?
|
## What’s Next?
|
||||||
Now that we’re familiar with Jasmine on its own, we’re ready to test an application.
|
Now that we’re familiar with Jasmine on its own, we’re ready to test an application.
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,8 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
We use it our `hero-detail.component.html` template to turn a hero name like “eeny weenie” into “Eeny Weenie”
|
We use it our `hero-detail.component.html` template to turn a hero name like “eeny weenie” into “Eeny Weenie”
|
||||||
|
|
||||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
code-example(format="linenums" language="html" escape="html").
|
||||||
|
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
|
||||||
code-example(format="linenums").
|
|
||||||
<h2>{{hero.name | initCaps}} is {{userName}}'s current super hero!</h2>
|
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
The code for `InitCapsPipe` in `init-caps-pipe.ts` is quite brief:
|
||||||
|
@ -61,9 +59,10 @@ figure.image-display
|
||||||
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.
|
||||||
|
|
||||||
```
|
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
|
||||||
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:
|
||||||
|
|
|
@ -24,7 +24,9 @@ include ../../../../_includes/_util-fns
|
||||||
Angular can do whatever we need it to do.
|
Angular can do whatever we need it to do.
|
||||||
We'll be covering a lot of ground at an introductory level but we’ll find plenty of links
|
We'll be covering a lot of ground at an introductory level but we’ll find plenty of links
|
||||||
to chapters with greater depth.
|
to chapters with greater depth.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## 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"
|
||||||
|
@ -59,7 +61,9 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
We can click a hero and have the router race us over to a "Hero Details" view
|
We can click a hero and have the router race us over to a "Hero Details" view
|
||||||
again.
|
again.
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
|
:markdown
|
||||||
## How We Roll
|
## How We Roll
|
||||||
|
|
||||||
We’ll build this Tour of Heroes together, step by step.
|
We’ll build this Tour of Heroes together, step by step.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
include ../../../../_includes/_util-fns
|
include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
# Once Upon a Time
|
# Once Upon a Time
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ include ../../../../_includes/_util-fns
|
||||||
└── package.json
|
└── package.json
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
## 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
|
||||||
|
@ -40,7 +39,7 @@ include ../../../../_includes/_util-fns
|
||||||
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.
|
||||||
|
|
||||||
.alert.is-helpful
|
.l-sub-section
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
@ -48,9 +47,8 @@ include ../../../../_includes/_util-fns
|
||||||
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
|
:markdown
|
||||||
# Show our Hero
|
## Show our Hero
|
||||||
We want to display Hero data in our app
|
We want to display Hero data in our app
|
||||||
|
|
||||||
Let's add two properties to our `AppComponent`, a `title` property for the application name and a `hero` property
|
Let's add two properties to our `AppComponent`, a `title` property for the application name and a `hero` property
|
||||||
|
@ -66,7 +64,7 @@ include ../../../../_includes/_util-fns
|
||||||
:markdown
|
:markdown
|
||||||
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="linenums").
|
code-example(format="").
|
||||||
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'
|
template: '<h1>{{title}}</h1><h2>{{hero}} details!</h2>'
|
||||||
:markdown
|
:markdown
|
||||||
The browser should refresh and display our title and hero.
|
The browser should refresh and display our title and hero.
|
||||||
|
@ -75,7 +73,7 @@ include ../../../../_includes/_util-fns
|
||||||
This is the "interpolation" form of one-way data binding;
|
This is the "interpolation" form of one-way data binding;
|
||||||
we can learn more about interpolation in the [Displaying Data chapter](displaying-data).
|
we can learn more about interpolation in the [Displaying Data chapter](displaying-data).
|
||||||
|
|
||||||
## Hero Object
|
### Hero object
|
||||||
|
|
||||||
At the moment, our hero is just a name. Our hero needs more properties.
|
At the moment, our hero is just a name. Our hero needs more properties.
|
||||||
Let's convert the `hero` from a literal string to a class.
|
Let's convert the `hero` from a literal string to a class.
|
||||||
|
@ -103,12 +101,12 @@ include ../../../../_includes/_util-fns
|
||||||
Because we changed the hero from a string to an object,
|
Because we changed the hero from a string to an object,
|
||||||
we update the binding in the template to refer to the hero’s `name` property.
|
we update the binding in the template to refer to the hero’s `name` property.
|
||||||
|
|
||||||
code-example(format="linenums").
|
code-example(format="").
|
||||||
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2>'
|
template: '<h1>{{title}}</h1><h2>{{hero.name}} details!</h2>'
|
||||||
:markdown
|
:markdown
|
||||||
The browser refreshes and continues to display our hero’s name.
|
The browser refreshes and continues to display our hero’s name.
|
||||||
|
|
||||||
## **Adding more HTML**
|
### Adding more HTML
|
||||||
Displaying a name is good, but we want to see all of our hero’s properties.
|
Displaying a name is good, but we want to see all of our hero’s properties.
|
||||||
We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`.
|
We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`.
|
||||||
|
|
||||||
|
@ -117,7 +115,7 @@ include ../../../../_includes/_util-fns
|
||||||
:markdown
|
:markdown
|
||||||
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
|
||||||
|
|
||||||
We could make a more readable template with string concatenation
|
We could make a more readable template with string concatenation
|
||||||
but that gets ugly fast, it is harder to read, and
|
but that gets ugly fast, it is harder to read, and
|
||||||
|
@ -147,9 +145,8 @@ 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
|
:markdown
|
||||||
# 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 +158,7 @@ include ../../../../_includes/_util-fns
|
||||||
<div><label>id: </label>{{hero.id}}</div>
|
<div><label>id: </label>{{hero.id}}</div>
|
||||||
<div>
|
<div>
|
||||||
<label>name: </label>
|
<label>name: </label>
|
||||||
<div><input value="{{hero.name}}" placeholder="name"></input></div>
|
<div><input value="{{hero.name}}" placeholder="name"></div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
:markdown
|
:markdown
|
||||||
|
@ -171,7 +168,7 @@ include ../../../../_includes/_util-fns
|
||||||
is not reflected in the `<h2>`. We won't get the desired behavior
|
is not reflected in the `<h2>`. We won't get the desired behavior
|
||||||
with a one-way binding to `<input>`.
|
with a one-way binding to `<input>`.
|
||||||
|
|
||||||
## Two-Way Binding
|
### Two-Way Binding
|
||||||
|
|
||||||
We intend to display the name of the hero in the `<input>`, change it,
|
We intend to display the name of the hero in the `<input>`, change it,
|
||||||
and see those changes wherever we bind to the hero’s name.
|
and see those changes wherever we bind to the hero’s name.
|
||||||
|
@ -179,22 +176,22 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
Let’s update the template to use the **`ng-model`** built-in directive for two-way binding.
|
Let’s update the template to use the **`ng-model`** built-in directive for two-way binding.
|
||||||
|
|
||||||
.alert.is-helpful
|
.l-sub-section
|
||||||
:markdown
|
:markdown
|
||||||
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
|
:markdown
|
||||||
Replace the `<input>` with the following HTML
|
Replace the `<input>` with the following HTML
|
||||||
|
|
||||||
```
|
code-example(language="html").
|
||||||
<input [(ng-model)]="hero.name" placeholder="name"></input>
|
<input [(ng-model)]="hero.name" placeholder="name">
|
||||||
```
|
|
||||||
|
:markdown
|
||||||
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.
|
||||||
Let’s fix that next.
|
Let’s fix that next.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
# 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.
|
||||||
A component must disclose every directive that appears in its template.
|
A component must disclose every directive that appears in its template.
|
||||||
|
@ -218,10 +215,10 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
Unfortunately when we view the app in the browser we still have an error:
|
Unfortunately when we view the app in the browser we still have an error:
|
||||||
|
|
||||||
```
|
code-example(language="html").
|
||||||
*EXCEPTION: No value accessor for ' ' in [null]*
|
EXCEPTION: No value accessor for ' ' in [null]
|
||||||
```
|
|
||||||
|
:markdown
|
||||||
Apparently declaring the `NgModel` is not quite enough.
|
Apparently declaring the `NgModel` is not quite enough.
|
||||||
|
|
||||||
## Declare Multiple Form Directives
|
## Declare Multiple Form Directives
|
||||||
|
@ -253,7 +250,7 @@ include ../../../../_includes/_util-fns
|
||||||
The browser refreshes. We see our hero again. We can edit the hero’s name and
|
The browser refreshes. We see our hero again. We can edit the hero’s name and
|
||||||
see the changes reflected immediately in the `<h2>`.
|
see the changes reflected immediately in the `<h2>`.
|
||||||
|
|
||||||
### Bundled Directives
|
### Bundled directives
|
||||||
Angular bundled the Form-related directives together in a convenient `FORM_DIRECTIVES` array.
|
Angular bundled the Form-related directives together in a convenient `FORM_DIRECTIVES` array.
|
||||||
That's all we need to remember to light up our template.
|
That's all we need to remember to light up our template.
|
||||||
|
|
||||||
|
@ -261,7 +258,9 @@ include ../../../../_includes/_util-fns
|
||||||
We too can bundle a collection of directives in an array, give it a catchy name,
|
We too can bundle a collection of directives in an array, give it a catchy name,
|
||||||
and plug that array into the `directives` property.
|
and plug that array into the `directives` property.
|
||||||
|
|
||||||
# The Road We’ve Travelled
|
.l-main-section
|
||||||
|
:markdown
|
||||||
|
## The Road We’ve Travelled
|
||||||
Let’s take stock of what we’ve built.
|
Let’s take stock of what we’ve built.
|
||||||
|
|
||||||
* Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
|
* Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
|
||||||
|
@ -290,7 +289,7 @@ include ../../../../_includes/_util-fns
|
||||||
<div><label>id: </label>{{hero.id}}</div>
|
<div><label>id: </label>{{hero.id}}</div>
|
||||||
<div>
|
<div>
|
||||||
<label>name: </label>
|
<label>name: </label>
|
||||||
<div><input value="{{hero.name}}" placeholder="name"></input></div>
|
<div><input [(ng-model)]="hero.name" placeholder="name"></div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
directives: [FORM_DIRECTIVES]
|
directives: [FORM_DIRECTIVES]
|
||||||
|
@ -305,8 +304,9 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
bootstrap(AppComponent);
|
bootstrap(AppComponent);
|
||||||
|
|
||||||
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
# 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.
|
||||||
We’ll learn more about how to retrieve lists, bind them to the
|
We’ll learn more about how to retrieve lists, bind them to the
|
||||||
|
|
|
@ -13,7 +13,7 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
# 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,
|
||||||
let’s verify we have the following structure after [Part 1](./toh-pt1.html).
|
let’s verify we have the following structure after [Part 1](./toh-pt1.html).
|
||||||
If not, we’ll need to go back to Part 1 and figure out what we missed.
|
If not, we’ll need to go back to Part 1 and figure out what we missed.
|
||||||
|
@ -28,7 +28,7 @@ include ../../../../_includes/_util-fns
|
||||||
| └── tsconfig.json
|
| └── tsconfig.json
|
||||||
└── package.json
|
└── package.json
|
||||||
:markdown
|
:markdown
|
||||||
## 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
|
||||||
|
@ -42,9 +42,11 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
|
||||||
# Displaying Our Heroes
|
.l-main-section
|
||||||
## Creating Heroes
|
:markdown
|
||||||
|
## Displaying Our Heroes
|
||||||
|
### Creating heroes
|
||||||
Let’s create an array of ten heroes at the bottom of `app.ts`.
|
Let’s create an array of ten heroes at the bottom of `app.ts`.
|
||||||
```
|
```
|
||||||
var HEROES: Hero[] = [
|
var HEROES: Hero[] = [
|
||||||
|
@ -65,20 +67,20 @@ include ../../../../_includes/_util-fns
|
||||||
We aspire to get this list of heroes from a web service, but let’s take small steps
|
We aspire to get this list of heroes from a web service, but let’s take small steps
|
||||||
on this road and start by displaying these mock heroes in the browser.
|
on this road and start by displaying these mock heroes in the browser.
|
||||||
|
|
||||||
## Exposing Heroes
|
### Exposing heroes
|
||||||
Let’s create a public property in `AppComponent` that exposes the heroes for binding.
|
Let’s create a public property in `AppComponent` that exposes the heroes for binding.
|
||||||
```
|
```
|
||||||
public heroes = HEROES;
|
public heroes = HEROES;
|
||||||
```
|
```
|
||||||
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.
|
||||||
.alert.is-helpful
|
.l-sub-section
|
||||||
:markdown
|
:markdown
|
||||||
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 we’ll get the heroes from a data service.
|
But we know that we’ll get the heroes from a data service.
|
||||||
Because 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
|
:markdown
|
||||||
## Displaying Heroes in a Template
|
### Displaying heroes in a template
|
||||||
Our component has`heroes`. Let’s create an unordered list in our template to display them.
|
Our component has`heroes`. Let’s create an unordered list in our template to display them.
|
||||||
We’ll insert the following chunk of HTML below the title and above the hero details.
|
We’ll insert the following chunk of HTML below the title and above the hero details.
|
||||||
```
|
```
|
||||||
|
@ -91,7 +93,7 @@ include ../../../../_includes/_util-fns
|
||||||
```
|
```
|
||||||
Now we have a template that we can fill with our heroes.
|
Now we have a template that we can fill with our heroes.
|
||||||
|
|
||||||
## Iterating Over Our Heroes with `ng-for`
|
### Listing heroes with ng-for
|
||||||
|
|
||||||
We want to bind the array of `heroes` in our component to our template, iterate over them,
|
We want to bind the array of `heroes` in our component to our template, iterate over them,
|
||||||
and display them individually.
|
and display them individually.
|
||||||
|
@ -101,47 +103,48 @@ include ../../../../_includes/_util-fns
|
||||||
```
|
```
|
||||||
<li *ng-for="#hero of heroes">
|
<li *ng-for="#hero of heroes">
|
||||||
```
|
```
|
||||||
.alert.is-important
|
.alert.is-critical
|
||||||
:markdown
|
:markdown
|
||||||
Do not neglect the leading asterisk (`*`) in front of `ng-for`!
|
The leading asterisk (`*`) in front of `ng-for` is a critical part of this syntax.
|
||||||
|
|
||||||
Although it is not part of the `ng-for` directive name,
|
.l-sub-section
|
||||||
it is a critical part of the syntax in this usage of `ng-for`.
|
|
||||||
:markdown
|
|
||||||
The (`*`) prefix to the `ng-for` indicates that the `<li>` element and its children
|
|
||||||
constitute a master template.
|
|
||||||
|
|
||||||
The `ng-for` directive iterates over the `heroes` array returned by the `AppComponent.heroes` property
|
|
||||||
and stamps out instances of this 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 corresponding template instance*”.
|
|
||||||
|
|
||||||
The `#` prefix before "hero" identifies the `hero` as a local template variable.
|
|
||||||
We can reference this variable within the template to access a hero’s properties.
|
|
||||||
|
|
||||||
.alert.is-helpful
|
|
||||||
:markdown
|
:markdown
|
||||||
|
The (`*`) prefix to `ng-for` indicates that the `<li>` element and its children
|
||||||
|
constitute a master template.
|
||||||
|
|
||||||
|
The `ng-for` directive iterates over the `heroes` array returned by the `AppComponent.heroes` property
|
||||||
|
and stamps out instances of this 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 corresponding template instance*”.
|
||||||
|
|
||||||
|
The `#` prefix before "hero" identifies the `hero` as a local template variable.
|
||||||
|
We can reference this variable within the template to access a hero’s properties.
|
||||||
|
|
||||||
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
|
:markdown
|
||||||
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 hero’s properties.
|
that uses the `hero` template variable to display the hero’s properties.
|
||||||
code-example.
|
|
||||||
|
code-example(format="linenums" language="html").
|
||||||
<li *ng-for="#hero of heroes">
|
<li *ng-for="#hero of heroes">
|
||||||
<span class="badge">{{hero.id}}</span> {{hero.name}}</a>
|
<span class="badge">{{hero.id}}</span> {{hero.name}}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
## Declaring NgFor
|
### 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.
|
||||||
```
|
|
||||||
|
code-example(language="html" ).
|
||||||
EXCEPTION:
|
EXCEPTION:
|
||||||
Can't bind to 'ngForOf' since it isn't a known property of the '<template>' element and
|
Can't bind to 'ngForOf' since it isn't a known property of the '<template>' element and
|
||||||
there are no matching directives with a corresponding property
|
there are no matching directives with a corresponding property
|
||||||
```
|
|
||||||
|
:markdown
|
||||||
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 didn’t tell the component about it.
|
We used `ng-for` in the template but we didn’t 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.
|
||||||
|
@ -159,14 +162,14 @@ include ../../../../_includes/_util-fns
|
||||||
```
|
```
|
||||||
After the browser refreshes, we see a list of heroes!
|
After the browser refreshes, we see a list of heroes!
|
||||||
|
|
||||||
## Styling Our Heroes
|
### Styling our heroes
|
||||||
Our list of heroes looks pretty bland.
|
Our list of heroes looks pretty bland.
|
||||||
We want to make it visually obvious to a user which hero we are hovering over and which hero is selected.
|
We want to make it visually obvious to a user which hero we are hovering over and which hero is selected.
|
||||||
|
|
||||||
Let’s add some styles to our component by setting the `styles` property on the `@Component` decorator
|
Let’s add some styles to our component by setting the `styles` property on the `@Component` decorator
|
||||||
to the following CSS classes:
|
to the following CSS classes:
|
||||||
```
|
```
|
||||||
styles: `
|
styles:[`
|
||||||
.heroes {list-style-type: none; margin-left: 1em; padding: 0; width: 10em;}
|
.heroes {list-style-type: none; margin-left: 1em; padding: 0; width: 10em;}
|
||||||
.heroes li { cursor: pointer; position: relative; left: 0; transition: all 0.2s ease; }
|
.heroes li { cursor: pointer; position: relative; left: 0; transition: all 0.2s ease; }
|
||||||
.heroes li:hover {color: #369; background-color: #EEE; left: .2em;}
|
.heroes li:hover {color: #369; background-color: #EEE; left: .2em;}
|
||||||
|
@ -179,9 +182,9 @@ include ../../../../_includes/_util-fns
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -1px;
|
left: -1px;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
}
|
}
|
||||||
.selected { background-color: #EEE; color: #369; }
|
.selected { background-color: #EEE; color: #369; }
|
||||||
`
|
`],
|
||||||
```
|
```
|
||||||
Notice that we again use the back-tick notation for multi-line strings.
|
Notice that we again use the back-tick notation for multi-line strings.
|
||||||
|
|
||||||
|
@ -205,7 +208,7 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
# 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.
|
||||||
We want the user to select a hero from our list, and have the selected hero appear in the details view.
|
We want the user to select a hero from our list, and have the selected hero appear in the details view.
|
||||||
|
@ -214,7 +217,7 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
Let’s connect the master to the detail through a `selectedHero` component property bound to a click event.
|
Let’s connect the master to the detail through a `selectedHero` component property bound to a click event.
|
||||||
|
|
||||||
## Click Event
|
### Click event
|
||||||
We modify the `<li>` by inserting an Angular event binding to its click event.
|
We modify the `<li>` by inserting an Angular event binding to its click event.
|
||||||
|
|
||||||
code-example(format="linenums").
|
code-example(format="linenums").
|
||||||
|
@ -230,11 +233,11 @@ include ../../../../_includes/_util-fns
|
||||||
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.
|
||||||
That’s the same `hero` variable we defined previously in the `ng-for`.
|
That’s the same `hero` variable we defined previously in the `ng-for`.
|
||||||
.alert.is-helpful
|
.l-sub-section
|
||||||
:markdown
|
:markdown
|
||||||
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
|
:markdown
|
||||||
## Add the click handler
|
### Add the click handler
|
||||||
Our event binding refers to an `onSelect` method that doesn’t exist yet.
|
Our event binding refers to an `onSelect` method that doesn’t exist yet.
|
||||||
We’ll add that method to our component now.
|
We’ll add that method to our component now.
|
||||||
|
|
||||||
|
@ -242,7 +245,7 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
Our component doesn’t have a “selected hero” yet either. We’ll start there.
|
Our component doesn’t have a “selected hero” yet either. We’ll start there.
|
||||||
|
|
||||||
### Expose the Selected Hero
|
### Expose the selected hero
|
||||||
We no longer need the static `hero` property of the `AppComponent`.
|
We no longer need the static `hero` property of the `AppComponent`.
|
||||||
**Replace** it with this simple `selectedHero` property:
|
**Replace** it with this simple `selectedHero` property:
|
||||||
```
|
```
|
||||||
|
@ -269,14 +272,16 @@ include ../../../../_includes/_util-fns
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
### Hide the empty detail with NgIf
|
### 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.
|
||||||
The `selectedHero` is `undefined`.
|
The `selectedHero` is `undefined`.
|
||||||
That’s why we'll see the following error in the browser’s console:
|
That’s why we'll see the following error in the browser’s console:
|
||||||
```
|
|
||||||
|
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
|
||||||
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.
|
||||||
|
|
||||||
|
@ -285,7 +290,7 @@ include ../../../../_includes/_util-fns
|
||||||
We wrap the HTML hero detail content of our template with a `<div>`.
|
We wrap the HTML hero detail content of our template with a `<div>`.
|
||||||
Then we add the `ng-if` built-in directive and set it to the `selectedHero` property of our component.
|
Then we add the `ng-if` built-in directive and set it to the `selectedHero` property of our component.
|
||||||
|
|
||||||
code-example(format="linenums").
|
code-example(format="linenums").
|
||||||
<div *ng-if="selectedHero">
|
<div *ng-if="selectedHero">
|
||||||
<h2>{{selectedHero.name}} details!</h2>
|
<h2>{{selectedHero.name}} details!</h2>
|
||||||
<div><label>id: </label>{{selectedHero.id}}</div>
|
<div><label>id: </label>{{selectedHero.id}}</div>
|
||||||
|
@ -294,18 +299,17 @@ include ../../../../_includes/_util-fns
|
||||||
<input [(ng-model)]="selectedHero.name" placeholder="name"></input>
|
<input [(ng-model)]="selectedHero.name" placeholder="name"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
.alert.is-important
|
.alert.is-critical
|
||||||
:markdown
|
:markdown
|
||||||
Do not neglect the leading asterisk (`*`) in front of `ng-if`.
|
Remember that the leading asterisk (`*`) in front of `ng-if` is
|
||||||
It's a critical part of the syntax in this usage of `ng-if`.
|
a critical part of this syntax.
|
||||||
:markdown
|
:markdown
|
||||||
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 no hero detail elements and no bindings to worry about.
|
There will 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
|
||||||
.alert.is-helpful
|
|
||||||
:markdown
|
:markdown
|
||||||
`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.
|
||||||
|
@ -333,7 +337,7 @@ include ../../../../_includes/_util-fns
|
||||||
When we click on a hero in the list, the selected hero displays in the hero details.
|
When we click on a hero in the list, the selected hero displays in the hero details.
|
||||||
Everything is working as we expect.
|
Everything is working as we expect.
|
||||||
|
|
||||||
### Styling the Selection
|
### Styling the selection
|
||||||
|
|
||||||
We see the selected hero in the details area below but we can’t quickly locate that hero in the list above.
|
We see the selected hero in the details area below but we can’t quickly locate that hero in the list above.
|
||||||
We can fix that by applying the `selected` CSS class to the appropriate `<li>` in the master list.
|
We can fix that by applying the `selected` CSS class to the appropriate `<li>` in the master list.
|
||||||
|
@ -356,7 +360,7 @@ include ../../../../_includes/_util-fns
|
||||||
```
|
```
|
||||||
What do we do with this method and its peculiar result?
|
What do we do with this method and its peculiar result?
|
||||||
|
|
||||||
### NgClass
|
### ng-class
|
||||||
We’ll add the `ng-class`built-in directive to the `<li>` element in our template and bind it to `getSelectedClass`.
|
We’ll add the `ng-class`built-in directive to the `<li>` element in our template and bind it to `getSelectedClass`.
|
||||||
It’s no coincidence that the value returned by `getSelectedClass` is exactly what the `ng-class` requires
|
It’s no coincidence that the value returned by `getSelectedClass` is exactly what the `ng-class` requires
|
||||||
to add or remove the `selected` class to each hero’s display.
|
to add or remove the `selected` class to each hero’s display.
|
||||||
|
@ -367,20 +371,16 @@ include ../../../../_includes/_util-fns
|
||||||
<span class="badge">{{hero.id}}</span> {{hero.name}}</a>
|
<span class="badge">{{hero.id}}</span> {{hero.name}}</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
.alert.is-helpful
|
|
||||||
:markdown
|
|
||||||
Learn more about `ng-class` in the
|
|
||||||
[Template Syntax](../guide/template-syntax.html#ng-class) chapter
|
|
||||||
|
|
||||||
:markdown
|
:markdown
|
||||||
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.
|
||||||
|
|
||||||
.alert.is-helpful
|
.l-sub-section
|
||||||
:markdown
|
:markdown
|
||||||
Learn more about about one-way property data binding in the
|
Learn more about [ng-class](../guide/template-syntax.html#ng-class)
|
||||||
[Template Syntax](../guide/template-syntax.html#property-binding) chapter
|
and [Property Binding](../guide/template-syntax.html#property-binding)
|
||||||
|
in the Template Syntax chapter
|
||||||
:markdown
|
:markdown
|
||||||
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 component’s `directives` array as we’ve done twice before.
|
in the component’s `directives` array as we’ve done twice before.
|
||||||
|
@ -428,14 +428,15 @@ include ../../../../_includes/_util-fns
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:markdown
|
:markdown
|
||||||
# The Road We’ve Travelled
|
## The Road We’ve Travelled
|
||||||
Here’s what we achieved in this chapter:
|
Here’s what we achieved in this chapter:
|
||||||
|
|
||||||
* Our Tour of Heroes now displays a list of selectable heroes
|
* Our Tour of Heroes now displays a list of selectable heroes
|
||||||
* We added the ability to select a hero and show the hero’s details
|
* We added the ability to select a hero and show the hero’s details
|
||||||
* We learned how to use the built-in directives `ng-if`, `ng-for` and `ng-class` in a component’s template
|
* We learned how to use the built-in directives `ng-if`, `ng-for` and `ng-class` in a component’s template
|
||||||
|
|
||||||
## The Road Ahead
|
### The Road Ahead
|
||||||
Our Tour of Heroes has grown, but it’s far from complete.
|
Our Tour of Heroes has grown, but it’s 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.
|
||||||
We’ll learn more about these tasks in the coming tutorial chapters.
|
We’ll learn more about these tasks in the coming tutorial chapters.
|
||||||
|
|
Loading…
Reference in New Issue