Angular2 The Tour of Heroes tutorial に挑戦してみる 6
ROUTING 後半戦
https://angular.io/docs/ts/latest/tutorial/toh-pt5.html
Add HeroService.getHero()
getHero(id: number): Promise<Hero> { // getHero(id) で、idを引数に取る関数 // idの型はnumber, getHeroのclassは、Hero. return this.getHeroes() // getHeroesで値の取得に成功したら .then(heroes => heroes.find(hero => hero.id === id)); // heroes は、heroesの中からid が一致するものになる }
class HeroService(): ... def getHero(id): if self.getHeroes(): hero = heroes.get(id=id)
Find the way back
- 戻るボタンを作る
goBack(): void{ this.location.back(); }
<div *ngIf="hero"> <h2>{{hero.name}} details!</h2> <div> <label>id: </label>{{hero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="hero.name" placeholder="name" /> </div> <button (click)="goBack()">Back</button> </div>
@Component({ selector: 'hero-detail', templateUrl: './hero-detail.component.html', })
Select a dashboard hero
<a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
- routerLink がhrefみたいなもんか。[]がついているということは、bindingされるということかな。
Refactor routes to a Routing Module
- Routing機能を別ファイルに移す。app-routing.module.tsを作成する
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { DashboardComponent } from './dashboard.component'; import { HeroesComponent } from './heroes.component'; import { HeroDetailComponent } from './hero-detail.component'; const routes: Routes = [ //const(変更不可)のroutesをRoutes classで定義する。Routes型は、@angular/routerからimportする。 { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, { path: 'dashboard', component: DashboardComponent }, { path: 'detail/:id', component: HeroDetailComponent }, { path: 'heroes', component: HeroesComponent } ]; @NgModule({ // ngModuleデコレータを使う>なぜだ? imports: [ RouterModule.forRoot(routes) ], // RouterModuleのforRootで、routesをimportsする exports: [ RouterModule ] // それをRouterModuleとして、exportする。これでRouterModuleでどこでも使える }) export class AppRoutingModule {} // 最後にこのModuleクラスをAppRoutingModule classとしてexportする。
- The Routing Module pulls the routes into a variable. The variable clarifies the routing module pattern in case you export the module in the future.
- The Routing Module adds RouterModule.forRoot(routes) to imports.
- The Routing Module adds RouterModule to exports so that the components in the companion module have access to Router declarables, such as RouterLink and RouterOutlet.
- There are no declarations. Declarations are the responsibility of the companion module.
- If you have guard services, the Routing Module adds module providers. (There are none in this example.)
Select a hero in the HeroesComponent
template: ` <h1>{{title}}</h1> <h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" // hero == selectedHeroの場合、class=selectedになる (click)="onSelect(hero)"> // click時に、onSelect(hero)を実行する <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <hero-detail [hero]="selectedHero"></hero-detail> `,
- onSelect の中身は、以下の通り。
onSelect(hero: Hero): void { this.selectedHero = hero; // selectedHeroにheroを代入する }
- つまり heroをclick->selectedHeroに、heroを代入->hero-detail タグに、selectedHeroを[hero]に代入->hero-detail component起動 って感じかな!
Add the mini detail
<div *ngIf="selectedHero"> <h2> {{selectedHero.name | uppercase}} is my hero </h2> <button (click)="gotoDetail()">View Details</button> </div>
*ngif
= “selectedHero” がある場合 > selectedHero.nameをすべて大文字で表示する。ViewDetails をclick するとgotoDetai()が起動する。
Move content out of the component file
- くっつけると以下のような感じ heroes.component.html。
<h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <div *ngIf="selectedHero"> <h2> {{selectedHero.name | uppercase}} is my hero </h2> <button (click)="gotoDetail()">View Details</button> </div>
- herose.component.tsは、以下のように修正する。
@Component({ selector: 'my-heroes', // css-selector名 templateUrl: './heroes.component.html', // templateファイルの場所 styleUrls: [ './heroes.component.css' ] // styleファイルの場所 })
@Component
と export class Componentの関係は、レンダリングに近いのかな。
Update the HeroesComponent class
- gotoDetailメソッドを定義する
gotoDetail(): void { // void returnが無い関数 this.router.navigate(['/detail', this.selectedHero.id]); // thisってのは、templateをレンダリングしたページのこと?router.navigateで、/detail idのurlにアクセスするメソッド }
Style the navigation links
app.component.ts
のtemplateを修正する。
template: ` <h1>{{title}}</h1> <nav> <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a> <a routerLink="/heroes" routerLinkActive="active">Heroes</a> </nav> <router-outlet></router-outlet> `,
- routerLink でhrefでアクセスする場合は、何が違うのか?routerLinkでアクセスすると、router-outletが機能するとかそんな感じかな〜。
- routerLinkActiveは、activeかどうかのstatusを設定できる。
- router-outlet で、routerの接続先のcomponentの内容を表示できる。
まとめ
- router-outlet, routerの使い方をざっくりまとめると以下のような流れなのかな。templateを基準に考えると自分は理解しやすい気がした。
<h1>{{title}}</h1> <nav> <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a> <a routerLink="/heroes" routerLinkActive="active">Heroes</a> </nav> <router-outlet></router-outlet> <!-- ここで、routerLink先のcomponentが呼び出されて表示される --> <!-- dashboardの場合は以下のtemplateが展開される ここでは、さらにrouterLinkで、detailページが表示される--> <h3>Top Heroes</h3> <div class="grid grid-pad"> <div *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4"> <div class="module hero"> <h4>{{hero.name}}</h4> </div> </div> </div> <!-- dashboardの場合は以下のtemplateが展開される --> <!-- routerLink で、heroのdetailページにアクセスすると以下のページが開く (router-outletではないため、たぶん、Dashboardのtemplate自体が以下のページに変更される)--> <div *ngIf="hero"> <h2>{{hero.name}} details!</h2> <div> <label>id: </label>{{hero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="hero.name" placeholder="name" /> </div> <button (click)="goBack()">Back</button> </div> <!-- detailpage終了 --> <!-- goBack()で、前の状態に戻る つまりdashboard viewに戻る--> <!-- <a routerLink="/heroes" routerLinkActive="active">Heroes</a> にアクセスした場合--> <!-- <router-outlet></router-outlet>にrouterLinkでアクセスしたcomponentのtemplateを展開する --> <h2>My Heroes</h2> <ul class="heroes"> <li *ngFor="let hero of heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)"> <span class="badge">{{hero.id}}</span> {{hero.name}} </li> </ul> <div *ngIf="selectedHero"> <h2> {{selectedHero.name | uppercase}} is my hero </h2> <button (click)="gotoDetail()">View Details</button> </div> <!-- hero名をclickすると、idと名前がページ下部に表示される --> <!-- clickすると、gotoDetail()が起動して、Detailページのtemplateが展開される --> <div *ngIf="hero"> <h2>{{hero.name}} details!</h2> <div> <label>id: </label>{{hero.id}}</div> <div> <label>name: </label> <input [(ngModel)]="hero.name" placeholder="name" /> </div> <button (click)="goBack()">Back</button> </div>