committed by
Miško Hevery
parent
cb848b9410
commit
8f084d7214
@@ -1,8 +1,4 @@
|
||||
/* HeroesComponent's private CSS styles */
|
||||
.selected {
|
||||
background-color: #CFD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes {
|
||||
margin: 0 0 2em 0;
|
||||
list-style-type: none;
|
||||
@@ -19,18 +15,18 @@
|
||||
height: 1.6em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes li:hover {
|
||||
color: #607D8B;
|
||||
background-color: #DDD;
|
||||
left: .1em;
|
||||
}
|
||||
.heroes .text {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
.heroes li.selected {
|
||||
background-color: #CFD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes .badge {
|
||||
display: inline-block;
|
||||
|
||||
@@ -34,4 +34,7 @@ export class HeroesComponent implements OnInit {
|
||||
this.selectedHero = hero;
|
||||
}
|
||||
// #enddocregion on-select
|
||||
// #docregion component
|
||||
}
|
||||
// #enddocregion component
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
/* HeroesComponent's private CSS styles */
|
||||
.selected {
|
||||
background-color: #CFD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes {
|
||||
margin: 0 0 2em 0;
|
||||
list-style-type: none;
|
||||
@@ -19,18 +15,18 @@
|
||||
height: 1.6em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes li:hover {
|
||||
color: #607D8B;
|
||||
background-color: #DDD;
|
||||
left: .1em;
|
||||
}
|
||||
.heroes .text {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
.heroes li.selected {
|
||||
background-color: #CFD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes .badge {
|
||||
display: inline-block;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
/* HeroesComponent's private CSS styles */
|
||||
.selected {
|
||||
background-color: #CFD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes {
|
||||
margin: 0 0 2em 0;
|
||||
list-style-type: none;
|
||||
@@ -19,18 +15,18 @@
|
||||
height: 1.6em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC !important;
|
||||
color: white;
|
||||
}
|
||||
.heroes li:hover {
|
||||
color: #607D8B;
|
||||
background-color: #DDD;
|
||||
left: .1em;
|
||||
}
|
||||
.heroes .text {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
.heroes li.selected {
|
||||
background-color: #CFD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes li.selected:hover {
|
||||
background-color: #BBD8DC;
|
||||
color: white;
|
||||
}
|
||||
.heroes .badge {
|
||||
display: inline-block;
|
||||
@@ -43,8 +39,6 @@
|
||||
left: -1px;
|
||||
top: -4px;
|
||||
height: 1.8em;
|
||||
min-width: 16px;
|
||||
text-align: right;
|
||||
margin-right: .8em;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { HeroesComponent } from './heroes/heroes.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'heroes', component: HeroesComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
@@ -7,9 +7,7 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
// #docregion import-dashboard
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
// #enddocregion import-dashboard
|
||||
// #docregion heroes-route
|
||||
import { HeroesComponent } from './heroes/heroes.component';
|
||||
// #enddocregion heroes-route
|
||||
// #docregion import-herodetail
|
||||
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
|
||||
// #enddocregion import-herodetail
|
||||
@@ -39,7 +37,9 @@ const routes: Routes = [
|
||||
imports: [ RouterModule.forRoot(routes) ],
|
||||
// #enddocregion ngmodule-imports
|
||||
// #docregion v1
|
||||
// #docregion export-routermodule
|
||||
exports: [ RouterModule ]
|
||||
// #enddocregion export-routermodule
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
// #enddocregion , v1
|
||||
|
||||
@@ -23,13 +23,17 @@ import { HeroSearchComponent } from './hero-search/hero-search.component';
|
||||
// #docregion v1
|
||||
import { MessagesComponent } from './messages/messages.component';
|
||||
|
||||
// #docregion import-httpclientmodule
|
||||
@NgModule({
|
||||
imports: [
|
||||
// #enddocregion import-httpclientmodule
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
AppRoutingModule,
|
||||
// #docregion in-mem-web-api-imports
|
||||
// #docregion import-httpclientmodule
|
||||
HttpClientModule,
|
||||
// #enddocregion import-httpclientmodule
|
||||
|
||||
// The HttpClientInMemoryWebApiModule module intercepts HTTP requests
|
||||
// and returns simulated server responses.
|
||||
@@ -38,7 +42,9 @@ import { MessagesComponent } from './messages/messages.component';
|
||||
InMemoryDataService, { dataEncapsulation: false }
|
||||
)
|
||||
// #enddocregion in-mem-web-api-imports
|
||||
// #docregion import-httpclientmodule
|
||||
],
|
||||
// #enddocregion import-httpclientmodule
|
||||
declarations: [
|
||||
AppComponent,
|
||||
DashboardComponent,
|
||||
@@ -50,6 +56,9 @@ import { MessagesComponent } from './messages/messages.component';
|
||||
// #docregion v1
|
||||
],
|
||||
bootstrap: [ AppComponent ]
|
||||
// #docregion import-httpclientmodule
|
||||
})
|
||||
// #enddocregion import-httpclientmodule
|
||||
|
||||
export class AppModule { }
|
||||
// #enddocregion , v1
|
||||
|
||||
@@ -13,11 +13,6 @@ import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { Hero } from './hero';
|
||||
import { MessageService } from './message.service';
|
||||
|
||||
// #docregion http-options
|
||||
const httpOptions = {
|
||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
|
||||
};
|
||||
// #enddocregion http-options
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HeroService {
|
||||
@@ -26,6 +21,12 @@ export class HeroService {
|
||||
private heroesUrl = 'api/heroes'; // URL to web api
|
||||
// #enddocregion heroesUrl
|
||||
|
||||
// #docregion http-options
|
||||
httpOptions = {
|
||||
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
|
||||
};
|
||||
// #enddocregion http-options
|
||||
|
||||
// #docregion ctor
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
@@ -96,7 +97,7 @@ export class HeroService {
|
||||
// #docregion addHero
|
||||
/** POST: add a new hero to the server */
|
||||
addHero (hero: Hero): Observable<Hero> {
|
||||
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
|
||||
return this.http.post<Hero>(this.heroesUrl, hero, this.httpOptions).pipe(
|
||||
tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)),
|
||||
catchError(this.handleError<Hero>('addHero'))
|
||||
);
|
||||
@@ -109,7 +110,7 @@ export class HeroService {
|
||||
const id = typeof hero === 'number' ? hero : hero.id;
|
||||
const url = `${this.heroesUrl}/${id}`;
|
||||
|
||||
return this.http.delete<Hero>(url, httpOptions).pipe(
|
||||
return this.http.delete<Hero>(url, this.httpOptions).pipe(
|
||||
tap(_ => this.log(`deleted hero id=${id}`)),
|
||||
catchError(this.handleError<Hero>('deleteHero'))
|
||||
);
|
||||
@@ -119,7 +120,7 @@ export class HeroService {
|
||||
// #docregion updateHero
|
||||
/** PUT: update the hero on the server */
|
||||
updateHero (hero: Hero): Observable<any> {
|
||||
return this.http.put(this.heroesUrl, hero, httpOptions).pipe(
|
||||
return this.http.put(this.heroesUrl, hero, this.httpOptions).pipe(
|
||||
tap(_ => this.log(`updated hero id=${hero.id}`)),
|
||||
catchError(this.handleError<any>('updateHero'))
|
||||
);
|
||||
|
||||
@@ -13,13 +13,11 @@ Using the Angular CLI, generate a new component named `heroes`.
|
||||
</code-example>
|
||||
|
||||
The CLI creates a new folder, `src/app/heroes/`, and generates
|
||||
the four files of the `HeroesComponent`.
|
||||
the three files of the `HeroesComponent` along with a test file.
|
||||
|
||||
The `HeroesComponent` class file is as follows:
|
||||
|
||||
<code-example
|
||||
path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1"
|
||||
header="app/heroes/heroes.component.ts (initial version)" linenums="false">
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" header="app/heroes/heroes.component.ts (initial version)" linenums="false">
|
||||
</code-example>
|
||||
|
||||
You always import the `Component` symbol from the Angular core library
|
||||
@@ -38,13 +36,13 @@ The CLI generated three metadata properties:
|
||||
The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors),
|
||||
`'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
|
||||
|
||||
The `ngOnInit` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
|
||||
Angular calls `ngOnInit` shortly after creating a component.
|
||||
The `ngOnInit()` is a [lifecycle hook](guide/lifecycle-hooks#oninit).
|
||||
Angular calls `ngOnInit()` shortly after creating a component.
|
||||
It's a good place to put initialization logic.
|
||||
|
||||
Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`.
|
||||
|
||||
### Add a _hero_ property
|
||||
### Add a `hero` property
|
||||
|
||||
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
|
||||
|
||||
@@ -54,17 +52,17 @@ Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
|
||||
### Show the hero
|
||||
|
||||
Open the `heroes.component.html` template file.
|
||||
Delete the default text generated by the Angular CLI and
|
||||
replace it with a data binding to the new `hero` property.
|
||||
Delete the default text generated by the Angular CLI and
|
||||
replace it with a data binding to the new `hero` property.
|
||||
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" header="heroes.component.html" region="show-hero-1" linenums="false">
|
||||
</code-example>
|
||||
|
||||
## Show the _HeroesComponent_ view
|
||||
## Show the `HeroesComponent` view
|
||||
|
||||
To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`.
|
||||
|
||||
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
|
||||
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
|
||||
So add an `<app-heroes>` element to the `AppComponent` template file, just below the title.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.component.html" header="src/app/app.component.html" linenums="false">
|
||||
@@ -102,10 +100,7 @@ The page no longer displays properly because you changed the hero from a string
|
||||
Update the binding in the template to announce the hero's name
|
||||
and show both `id` and `name` in a details layout like this:
|
||||
|
||||
<code-example
|
||||
path="toh-pt1/src/app/heroes/heroes.component.1.html"
|
||||
region="show-hero-2"
|
||||
header="heroes.component.html (HeroesComponent's template)" linenums="false">
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="show-hero-2" header="heroes.component.html (HeroesComponent's template)" linenums="false">
|
||||
</code-example>
|
||||
|
||||
The browser refreshes and displays the hero's information.
|
||||
@@ -113,14 +108,12 @@ The browser refreshes and displays the hero's information.
|
||||
## Format with the _UppercasePipe_
|
||||
|
||||
Modify the `hero.name` binding like this.
|
||||
<code-example
|
||||
path="toh-pt1/src/app/heroes/heroes.component.html"
|
||||
region="pipe">
|
||||
<code-example path="toh-pt1/src/app/heroes/heroes.component.html" header="src/app/heroes/heroes.component.html" region="pipe">
|
||||
</code-example>
|
||||
|
||||
The browser refreshes and now the hero's name is displayed in capital letters.
|
||||
|
||||
The word `uppercase` in the interpolation binding,
|
||||
The word `uppercase` in the interpolation binding,
|
||||
right after the pipe operator ( | ),
|
||||
activates the built-in `UppercasePipe`.
|
||||
|
||||
@@ -133,7 +126,7 @@ Users should be able to edit the hero name in an `<input>` textbox.
|
||||
|
||||
The textbox should both _display_ the hero's `name` property
|
||||
and _update_ that property as the user types.
|
||||
That means data flow from the component class _out to the screen_ and
|
||||
That means data flows from the component class _out to the screen_ and
|
||||
from the screen _back to the class_.
|
||||
|
||||
To automate that data flow, setup a two-way data binding between the `<input>` form element and the `hero.name` property.
|
||||
@@ -146,7 +139,7 @@ Refactor the details area in the `HeroesComponent` template so it looks like thi
|
||||
|
||||
</code-example>
|
||||
|
||||
**[(ngModel)]** is Angular's two-way data binding syntax.
|
||||
**[(ngModel)]** is Angular's two-way data binding syntax.
|
||||
|
||||
Here it binds the `hero.name` property to the HTML textbox so that data can flow _in both directions:_ from the `hero.name` property to the textbox, and from the textbox back to the `hero.name`.
|
||||
|
||||
@@ -162,7 +155,7 @@ Template parse errors:
|
||||
Can't bind to 'ngModel' since it isn't a known property of 'input'.
|
||||
</code-example>
|
||||
|
||||
Although `ngModel` is a valid Angular directive, it isn't available by default.
|
||||
Although `ngModel` is a valid Angular directive, it isn't available by default.
|
||||
|
||||
It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
|
||||
|
||||
@@ -170,7 +163,7 @@ It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
|
||||
|
||||
Angular needs to know how the pieces of your application fit together
|
||||
and what other files and libraries the app requires.
|
||||
This information is called _metadata_
|
||||
This information is called _metadata_.
|
||||
|
||||
Some of the metadata is in the `@Component` decorators that you added to your component classes.
|
||||
Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators.
|
||||
@@ -182,7 +175,7 @@ This is where you _opt-in_ to the `FormsModule`.
|
||||
|
||||
### Import _FormsModule_
|
||||
|
||||
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
|
||||
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (FormsModule symbol import)"
|
||||
region="formsmodule-js-import">
|
||||
@@ -190,13 +183,13 @@ Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the
|
||||
|
||||
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
|
||||
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts ( @NgModule imports)"
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="app.module.ts (@NgModule imports)"
|
||||
region="ng-imports">
|
||||
</code-example>
|
||||
|
||||
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
|
||||
|
||||
### Declare _HeroesComponent_
|
||||
### Declare `HeroesComponent`
|
||||
|
||||
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
|
||||
|
||||
@@ -206,11 +199,11 @@ So why did the application work?
|
||||
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
|
||||
|
||||
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" region="heroes-import" >
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="heroes-import" >
|
||||
</code-example>
|
||||
|
||||
The `HeroesComponent` is declared in the `@NgModule.declarations` array.
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" region="declarations">
|
||||
<code-example path="toh-pt1/src/app/app.module.ts" header="src/app/app.module.ts" region="declarations">
|
||||
</code-example>
|
||||
|
||||
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
|
||||
@@ -228,7 +221,7 @@ Your app should look like this <live-example></live-example>. Here are the code
|
||||
<code-pane header="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/app.module.ts"
|
||||
<code-pane header="src/app/app.module.ts"
|
||||
path="toh-pt1/src/app/app.module.ts">
|
||||
</code-pane>
|
||||
|
||||
@@ -238,7 +231,7 @@ Your app should look like this <live-example></live-example>. Here are the code
|
||||
<code-pane header="src/app/app.component.html" path="toh-pt1/src/app/app.component.html">
|
||||
</code-pane>
|
||||
|
||||
<code-pane header="src/app/hero.ts"
|
||||
<code-pane header="src/app/hero.ts"
|
||||
path="toh-pt1/src/app/hero.ts">
|
||||
</code-pane>
|
||||
|
||||
@@ -247,10 +240,10 @@ Your app should look like this <live-example></live-example>. Here are the code
|
||||
## Summary
|
||||
|
||||
* You used the CLI to create a second `HeroesComponent`.
|
||||
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
|
||||
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
|
||||
* You applied the `UppercasePipe` to format the name.
|
||||
* You used two-way data binding with the `ngModel` directive.
|
||||
* You learned about the `AppModule`.
|
||||
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
|
||||
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
|
||||
* You learned the importance of declaring components in the `AppModule`
|
||||
and appreciated that the CLI declared it for you.
|
||||
|
||||
@@ -21,19 +21,17 @@ header="src/app/mock-heroes.ts">
|
||||
|
||||
## Displaying heroes
|
||||
|
||||
You're about to display the list of heroes at the top of the `HeroesComponent`.
|
||||
|
||||
Open the `HeroesComponent` class file and import the mock `HEROES`.
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" header="src/app/heroes/heroes.component.ts (import HEROES)">
|
||||
</code-example>
|
||||
|
||||
In the same file (`HeroesComponent` class), define a component property called `heroes` to expose `HEROES` array for binding.
|
||||
In the same file (`HeroesComponent` class), define a component property called `heroes` to expose the `HEROES` array for binding.
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="component">
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" header="src/app/heroes/heroes.component.ts" region="component">
|
||||
</code-example>
|
||||
|
||||
### List heroes with _*ngFor_
|
||||
### List heroes with `*ngFor`
|
||||
|
||||
Open the `HeroesComponent` template file and make the following changes:
|
||||
|
||||
@@ -47,7 +45,7 @@ Make it look like this:
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" header="heroes.component.html (heroes template)" linenums="false">
|
||||
</code-example>
|
||||
|
||||
Now change the `<li>` to this:
|
||||
That shows one hero. To list them all, add an `*ngFor` to the `<li>` to iterate through the list of heroes:
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li">
|
||||
</code-example>
|
||||
@@ -55,10 +53,10 @@ Now change the `<li>` to this:
|
||||
The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive.
|
||||
It repeats the host element for each element in a list.
|
||||
|
||||
In this example
|
||||
The syntax in this example is as follows:
|
||||
|
||||
* `<li>` is the host element
|
||||
* `heroes` is the list from the `HeroesComponent` class.
|
||||
* `<li>` is the host element.
|
||||
* `heroes` holds the mock heroes list from the `HeroesComponent` class, the mock heroes list.
|
||||
* `hero` holds the current hero object for each iteration through the list.
|
||||
|
||||
<div class="alert is-important">
|
||||
@@ -127,9 +125,10 @@ This is an example of Angular's [event binding](guide/template-syntax#event-bind
|
||||
The parentheses around `click` tell Angular to listen for the `<li>` element's `click` event.
|
||||
When the user clicks in the `<li>`, Angular executes the `onSelect(hero)` expression.
|
||||
|
||||
`onSelect()` is a `HeroesComponent` method that you're about to write.
|
||||
Angular calls it with the `hero` object displayed in the clicked `<li>`,
|
||||
the same `hero` defined previously in the `*ngFor` expression.
|
||||
|
||||
In the next section, define an `onSelect()` method in `HeroesComponent` to
|
||||
display the hero that was defined in the `*ngFor` expression.
|
||||
|
||||
|
||||
### Add the click event handler
|
||||
|
||||
@@ -142,10 +141,11 @@ to the component's `selectedHero`.
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" header="src/app/heroes/heroes.component.ts (onSelect)" linenums="false">
|
||||
</code-example>
|
||||
|
||||
### Update the details template
|
||||
### Add a details section
|
||||
|
||||
The template still refers to the component's old `hero` property which no longer exists.
|
||||
Rename `hero` to `selectedHero`.
|
||||
Currently, you have a list in the component template. To click on a hero on the list
|
||||
and reveal details about that hero, you need a section for the details to render in the
|
||||
template. Add the following to `heroes.component.html` beneath the list section:
|
||||
|
||||
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" header="heroes.component.html (selected hero details)" linenums="false">
|
||||
</code-example>
|
||||
@@ -162,7 +162,7 @@ Open the browser developer tools and look in the console for an error message li
|
||||
|
||||
When the app starts, the `selectedHero` is `undefined` _by design_.
|
||||
|
||||
Binding expressions in the template that refer to properties of `selectedHero` — expressions like `{{selectedHero.name}}` — _must fail_ because there is no selected hero.
|
||||
Binding expressions in the template that refer to properties of `selectedHero`—expressions like `{{selectedHero.name}}`—_must fail_ because there is no selected hero.
|
||||
|
||||
|
||||
#### The fix - hide empty details with _*ngIf_
|
||||
@@ -192,7 +192,7 @@ The heroes appear in a list and details about the clicked hero appear at the bot
|
||||
|
||||
#### Why it works
|
||||
|
||||
When `selectedHero` is undefined, the `ngIf` removes the hero detail from the DOM. There are no `selectedHero` bindings to worry about.
|
||||
When `selectedHero` is undefined, the `ngIf` removes the hero detail from the DOM. There are no `selectedHero` bindings to consider.
|
||||
|
||||
When the user picks a hero, `selectedHero` has a value and
|
||||
`ngIf` puts the hero detail into the DOM.
|
||||
@@ -240,7 +240,7 @@ Here are the code files discussed on this page, including the `HeroesComponent`
|
||||
|
||||
<code-pane header="src/app/mock-heroes.ts" path="toh-pt2/src/app/mock-heroes.ts">
|
||||
</code-pane>
|
||||
|
||||
|
||||
<code-pane header="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts">
|
||||
</code-pane>
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ Amend the `@angular/core` import statement to include the `Input` symbol.
|
||||
|
||||
Add a `hero` property, preceded by the `@Input()` decorator.
|
||||
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false">
|
||||
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" header="src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false">
|
||||
</code-example>
|
||||
|
||||
That's the only change you should make to the `HeroDetailComponent` class.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+115
-158
File diff suppressed because it is too large
Load Diff
+171
-234
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user