2017-02-22 13:09:39 -05:00
|
|
|
@title
|
|
|
|
Master/Detail
|
|
|
|
|
|
|
|
@intro
|
2017-03-27 11:08:53 -04:00
|
|
|
Build a master/detail page with a list of heroes.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
@description
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
In this page, you'll expand the Tour of Heroes app to display a list of heroes, and
|
|
|
|
allow users to select a hero and display the hero's details.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
When you're done with this page, the app should look like this <live-example></live-example>.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## Where you left off
|
|
|
|
Before you continue with this page of the Tour of Heroes,
|
|
|
|
verify that you have the following structure after [The Hero Editor](tutorial/toh-pt1) page.
|
|
|
|
If your structure doesn't match, go back to that page to figure out what you missed.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-30 15:04:18 -04:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='filetree'>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
angular-tour-of-heroes
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class='children'>
|
|
|
|
|
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
src
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class='children'>
|
|
|
|
|
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
app
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class='children'>
|
|
|
|
|
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
app.component.ts
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
app.module.ts
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
main.ts
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
index.html
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
styles.css
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
systemjs.config.js
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
tsconfig.json
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-03-27 11:08:53 -04:00
|
|
|
node_modules ...
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
<div class='file'>
|
2017-02-22 13:09:39 -05:00
|
|
|
package.json
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-11 16:44:52 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## Keep the app transpiling and running
|
|
|
|
Enter the following command in the terminal window:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-30 15:04:18 -04:00
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
<code-example language="sh" class="code-shell">
|
2017-03-31 19:57:13 -04:00
|
|
|
npm start
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
This command runs the TypeScript compiler in "watch mode", recompiling automatically when the code changes.
|
|
|
|
The command simultaneously launches the app in a browser and refreshes the browser when the code changes.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
You can keep building the Tour of Heroes without pausing to recompile or refresh the browser.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## Displaying heroes
|
|
|
|
To display a list of heroes, you'll add heroes to the view's template.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
### Create heroes
|
|
|
|
Create an array of ten heroes.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.ts" region="hero-array" title="src/app/app.component.ts (hero array)">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The `HEROES` array is of type `Hero`, the class defined in the previous page.
|
|
|
|
Eventually this app will fetch the list of heroes from a web service, but for now
|
|
|
|
you can display mock heroes.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
### Expose heroes
|
|
|
|
Create a public property in `AppComponent` that exposes the heroes for binding.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="hero-array-1" title="app.component.ts (hero array property)">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The `heroes` type isn't defined because TypeScript infers it from the `HEROES` array.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="l-sub-section">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The hero data is separated from the class implementation
|
|
|
|
because ultimately the hero names will come from a data service.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
### Display hero names in a template
|
|
|
|
To display the hero names in an unordered list,
|
|
|
|
insert the following chunk of HTML below the title and above the hero details.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="heroes-template-1" title="app.component.ts (heroes template)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Now you can fill the template with hero names.
|
|
|
|
|
|
|
|
### List heroes with ngFor
|
|
|
|
|
2017-04-12 15:53:18 -04:00
|
|
|
The goal is to bind the array of heroes in the component to the template, iterate over them,
|
2017-03-27 11:08:53 -04:00
|
|
|
and display them individually.
|
|
|
|
|
|
|
|
Modify the `<li>` tag by adding the built-in directive `*ngFor`.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="heroes-ngfor-1" title="app.component.ts (ngFor)">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="l-sub-section">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The (`*`) prefix to `ngFor` is a critical part of this syntax.
|
|
|
|
It indicates that the `<li>` element and its children
|
2017-02-22 13:09:39 -05:00
|
|
|
constitute a master template.
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The `ngFor` directive iterates over the component's `heroes` array
|
|
|
|
and renders an instance of this template for each hero in that array.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The `let hero` part of the expression identifies `hero` as the template input variable,
|
|
|
|
which holds the current hero item for each iteration.
|
|
|
|
You can reference this variable within the template to access the current hero's properties.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Read more about `ngFor` and template input variables in the
|
2017-03-31 19:57:13 -04:00
|
|
|
[Showing an array property with *ngFor](guide/displaying-data#ngFor) section of the
|
2017-03-27 11:08:53 -04:00
|
|
|
[Displaying Data](guide/displaying-data) page and the
|
2017-03-31 19:57:13 -04:00
|
|
|
[ngFor](guide/template-syntax#ngFor) section of the
|
2017-03-27 11:08:53 -04:00
|
|
|
[Template Syntax](guide/template-syntax) page.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Within the `<li>` tags, add content
|
|
|
|
that uses the `hero` template variable to display the hero's properties.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="ng-for" title="app.component.ts (ngFor template)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
When the browser refreshes, a list of heroes appears.
|
|
|
|
|
|
|
|
### Style the heroes
|
|
|
|
Users should get a visual cue of which hero they are hovering over and which hero is selected.
|
|
|
|
|
|
|
|
To add styles to your component, set the `styles` property on the `@Component` decorator
|
2017-02-22 13:09:39 -05:00
|
|
|
to the following CSS classes:
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.ts" region="styles" title="src/app/app.component.ts (styles)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Remember to use the backtick notation for multi-line strings.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Adding these styles makes the file much longer. In a later page you'll move the styles to a separate file.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
When you assign styles to a component, they are scoped to that specific component.
|
|
|
|
These styles apply only to the `AppComponent` and don't affect the outer HTML.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The template for displaying heroes should look like this:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="heroes-styled" title="src/app/app.component.ts (styled heroes)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## Selecting a hero
|
|
|
|
The app now displays a list of heroes as well as a single hero in the details view. But
|
|
|
|
the list and the details view are not connected.
|
|
|
|
When users select a hero from the list, the selected hero should appear in the details view.
|
|
|
|
This UI pattern is known as "master/detail."
|
|
|
|
In this case, the _master_ is the heroes list and the _detail_ is the selected hero.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Next you'll connect the master to the detail through a `selectedHero` component property,
|
|
|
|
which is bound to a click event.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-12 15:53:18 -04:00
|
|
|
### Handle click events
|
2017-03-27 11:08:53 -04:00
|
|
|
Add a click event binding to the `<li>` like this:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="selectedHero-click" title="app.component.ts (template excerpt)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The parentheses identify the `<li>` element's `click` event as the target.
|
|
|
|
The `onSelect(hero)` expression calls the `AppComponent` method, `onSelect()`,
|
|
|
|
passing the template input variable `hero`, as an argument.
|
|
|
|
That's the same `hero` variable you defined previously in the `ngFor` directive.
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="l-sub-section">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Learn more about event binding at the
|
|
|
|
[User Input](guide/user-input) page and the
|
2017-03-31 19:57:13 -04:00
|
|
|
[Event binding](guide/template-syntax#event-binding) section of the
|
2017-03-27 11:08:53 -04:00
|
|
|
[Template Syntax](guide/template-syntax) page.
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
### Add a click handler to expose the selected hero
|
|
|
|
You no longer need the `hero` property because you're no longer displaying a single hero; you're displaying a list of heroes.
|
|
|
|
But the user will be able to select one of the heroes by clicking on it.
|
|
|
|
So replace the `hero` property with this simple `selectedHero` property:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.ts" region="selected-hero" title="src/app/app.component.ts (selectedHero)">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The hero names should all be unselected before the user picks a hero, so
|
|
|
|
you won't initialize the `selectedHero` as you did with `hero`.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
Add an `onSelect()` method that sets the `selectedHero` property to the `hero` that the user clicks.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.ts" region="on-select" title="src/app/app.component.ts (onSelect)" linenums="false">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The template still refers to the old `hero` property.
|
2017-04-12 15:53:18 -04:00
|
|
|
Bind to the new `selectedHero` property instead as follows:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="selectedHero-details" title="app.component.ts (template excerpt)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
### Hide the empty detail with ngIf
|
|
|
|
|
2017-04-12 15:53:18 -04:00
|
|
|
When the app loads, `selectedHero` is undefined.
|
|
|
|
The selected hero is initialized when the user clicks a hero's name.
|
2017-03-27 11:08:53 -04:00
|
|
|
Angular can't display properties of the undefined `selectedHero` and throws the following error,
|
|
|
|
visible in the browser's console:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-30 15:04:18 -04:00
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
<code-example format="nocode">
|
2017-03-31 19:57:13 -04:00
|
|
|
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Although `selectedHero.name` is displayed in the template,
|
|
|
|
you must keep the hero detail out of the DOM until there is a selected hero.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Wrap the HTML hero detail content of the template with a `<div>`.
|
|
|
|
Then add the `ngIf` built-in directive and set it to the `selectedHero` property of the component.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="ng-if" title="src/app/app.component.ts (ngIf)" linenums="false">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="alert is-critical">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Don't forget the asterisk (`*`) in front of `ngIf`.
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The app no longer fails and the list of names displays again in the browser.
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-04-12 15:53:18 -04:00
|
|
|
When there is no selected hero, the `ngIf` directive removes the hero detail HTML from the DOM.
|
2017-03-27 11:08:53 -04:00
|
|
|
There are no hero detail elements or bindings to worry about.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
When the user picks a hero, `selectedHero` becomes defined and
|
2017-02-22 13:09:39 -05:00
|
|
|
`ngIf` puts the hero detail content into the DOM and evaluates the nested bindings.
|
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="l-sub-section">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Read more about `ngIf` and `ngFor` in the
|
|
|
|
[Structural Directives](guide/structural-directives) page and the
|
2017-03-31 19:57:13 -04:00
|
|
|
[Built-in directives](guide/template-syntax#directives) section of the
|
2017-03-27 11:08:53 -04:00
|
|
|
[Template Syntax](guide/template-syntax) page.
|
|
|
|
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
### Style the selected hero
|
|
|
|
|
|
|
|
While the selected hero details appear below the list, it's difficult to identify the selected hero within the list itself.
|
|
|
|
|
|
|
|
In the `styles` metadata that you added above, there is a custom CSS class named `selected`.
|
|
|
|
To make the selected hero more visible, you'll apply this `selected` class to the `<li>` when the user clicks on a hero name.
|
|
|
|
For example, when the user clicks "Magneta", it should render with a distinctive but subtle background color
|
|
|
|
like this:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-30 15:04:18 -04:00
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
<figure class='image-display'>
|
2017-04-26 08:11:02 -04:00
|
|
|
<img src='content/images/guide/toh/heroes-list-selected.png' alt="Selected hero"></img>
|
2017-02-22 13:09:39 -05:00
|
|
|
</figure>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
In the template, add the following `[class.selected]` binding to the `<li>`:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="class-selected-1" title="app.component.ts (setting the CSS class)" linenums="false">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
When the expression (`hero === selectedHero`) is `true`, Angular adds the `selected` CSS class.
|
|
|
|
When the expression is `false`, Angular removes the `selected` class.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
<div class="l-sub-section">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
Read more about the `[class]` binding in the [Template Syntax](guide/template-syntax#ngClass "Template syntax: NgClass") guide.
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
|
2017-04-10 11:51:13 -04:00
|
|
|
</div>
|
2017-03-27 11:08:53 -04:00
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
The final version of the `<li>` looks like this:
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.1.html" region="class-selected-2" title="app.component.ts (styling each hero)" linenums="false">
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
After clicking "Magneta", the list should look like this:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-30 15:04:18 -04:00
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
<figure class='image-display'>
|
2017-04-26 08:11:02 -04:00
|
|
|
<img src='content/images/guide/toh/heroes-list-1.png' alt="Output of heroes list app"></img>
|
2017-02-22 13:09:39 -05:00
|
|
|
</figure>
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Here's the complete `app.component.ts` as of now:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-04-18 14:16:02 -04:00
|
|
|
<code-example path="toh-pt2/src/app/app.component.ts" title="src/app/app.component.ts">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-31 19:57:13 -04:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## The road you've travelled
|
2017-03-31 19:57:13 -04:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Here's what you achieved in this page:
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
* The Tour of Heroes app displays a list of selectable heroes.
|
|
|
|
* You added the ability to select a hero and show the hero's details.
|
|
|
|
* You learned how to use the built-in directives `ngIf` and `ngFor` in a component's template.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
Your app should look like this <live-example></live-example>.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
## The road ahead
|
|
|
|
You've expanded the Tour of Heroes app, but it's far from complete.
|
2017-04-12 15:53:18 -04:00
|
|
|
An app shouldn't be one monolithic component.
|
2017-04-18 14:16:02 -04:00
|
|
|
In the [next page](tutorial/toh-pt3), you'll split the app into subcomponents and make them work together.
|