読者です 読者をやめる 読者になる 読者になる

Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

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>