ふらぱいく

備忘録。いい加減つける

Angular 入門してみる 6

ルーティング 1
ルーティングの設定を行い,ページの遷移を実現。
社員一覧と社員の詳細を別のUrlで出力。今回も実装は後の方。

環境

  • Angular CLI: 8.0.1
  • Node: 12.3.1

お勉強

ルーティングとは?

httpやrailsの場合,httpリクエストによるページ遷移だったが,SPA(SinglePageApplication)ではコンポーネントで呼び出されるDOMだけを書き換えることによって,「見た目上」のページ遷移を実現する。
Angular はルーティングに対する便利なモジュールが存在するので,それを用いて実装。

RouteModule のimport

基本的な流れとして,RouteModule を読み込む,import 配列に追記,DOMで表示させたい場所を,ルーティング指定したコンポーネントを表示させる router-outlet タグに変更

import { RouteModule } from '@angular/router';
...
import [
   ...
   RouteModule
]
@Component({
   selector: 'my-app',
   template: `
      <h1>{{ title }} </h1>
      <--    <label> test </label>   --->   
      < router-outlet ></router-outlet> <-- 追記 -->
    `
})
...
export class AppComponent {
   title = 'タイトル';
}

遷移したページのコンポーネント

@Component({
   selector: 'my-page1',
   template: `
      page1に遷移しました.
   `
})
...

だがこのままではパスが指定されていないため遷移できない。

RouterModule の forRoute メソッド

RouterModule には forRoute メソッドが存在し,指定したパスに指定したコンポーネントを呼び出す。これによってDOMの書き換えによる見かけのページ遷移を行う。

import { RouteModule } from '@angular/router';
...
import [
   ...
   RouteModule.forRoot([
      {
         path: 'page1',
         component: ExampleComponent
      },
      {
         path: 'page2',
         component: Example2Component
      }
]

例えばリンクを押した際に指定したパスへ遷移する単純な実装の場合

@Component({
   selector: 'my-app',
   template: `
      <h1>{{ title }} </h1>
      <a routerLink="/page1"> page1へ遷移 </a>
      <a routerLink="/page2"> page2へ遷移 </a>
      <--    <label> test </label>   --->   
      < router-outlet ></router-outlet> <!-- 追記 -->
    `
...
export class AppComponent {
   title = 'タイトル';
}
@Component({
   selector: 'my-page1',
   template: `
      page1に遷移しました。
    `
})
@Component({
   selector: 'my-page2',
   template: `
      page2に遷移しました。
   `
})

実行結果
page1をクリックした場合

タイトル
page1に遷移しました。

page2をクリックした場合

タイトル
page2に遷移しました。
リダイレクト

リダイレクトとは,特定のページにアクセスがあった場合のページ遷移。 例外処理みたいな感じだけど違う。
例えばpage1にアクセスしたとき,page2 のDOMを表示させたいって場合。
redirectTo メソッド内を下記のように記述。

imports: [
   ...
   RouteModule.forRoute([
      {
         path: 'page1',
         redirectTo: 'page2',
         pathmatch: 'full'
      }
   ])
...

先程のページ遷移の例のように,page1のリンクへアクセスすると,page2のDOMが表示される。

タイトル
page2に遷移しました。

path に遷移元のパス,redirectTo に遷移させたいパス
pathmatch はURLが完全一致した場合という条件を意味する。これを記述しない場合,例えば上の例でいうと,page1/tempにアクセスした場合,page2 にリダイレクトをしてしまう。

リダイレクトに関しては次回実装を行う。

実装

実際に社員名簿管理アプリに実装。
今までは,トップページに社員一覧が表示されていたが,トップページには社員一覧というリンクを作り,そのページにアクセスしたときに一覧を映し出すよう実装。

新しいトップページと,社員一覧ページのファイルを作成

新たにトップページを作成し,社員一覧コンポーネントと分離する必要があるため,今まであったapp.component.ts を members.component.ts にリネーム。また,新しくapp.component.ts を作成。

import { Component, OnInit } from '@angular/core';
import { Member } from './member';
import {MemberService} from './member.service';

@Component({
  selector: 'my-members', // 変更
  template: `
    <h1>{{title}}</h1>
    <h2>社員一覧</h2>
    <ul class="members">
      <li *ngFor="let member of members"
          (click)="onSelect(member)"
          [class.selected]="member === selectedMember">
        <span class="badge">{{member.id}}</span> {{member.name}}
      </li>
    </ul>
    <member-detail [member]="selectedMember"></member-detail>
  `,
  style: ...
})
export class MembersComponent implements OnInit { // Component名も忘れず変更,module.tsへの記述も
  title = '自社社員名簿';
  members: Member[];
  selectedMember: Member;

  constructor(private memberService: MemberService) {
  }

  ngOnInit() {
    this.memberService.getMembers()
      .then(members => this.members = members);
  }

  onSelect(member: Member): void {
    this.selectedMember = member;
  }
}

新しくトップページになるapp.component.ts

import {Component} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <h2>{{title}}</h2>
    
    <!-- href の代わりに routerLinkを設定 -->
    <a routerLink="/members">社員一覧</a> 
    
    <!-- 表示させる場所に記述 -->
    <router-outlet></router-outlet>  
  `
})

export class AppComponent {
  title = '自社社員名簿';
}
Routerモジュールのimport
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import {RouterModule} from '@angular/router';

import {AppComponent} from './app.component';
import { MembersComponent }  from './members.component'; // 追加
import { MemberDetailComponent } from './member-detail.component';
import {MemberService} from './member.service';

@NgModule({
  imports:      [
    BrowserModule,
    FormsModule,
    // routerの設定
    RouterModule.forRoot([
      {
        path: 'members',  // pathにmemberを指定,
        component: MembersComponent  // MembersComponentを指定
      }
    ])
  ],
  declarations: [
    AppComponent,
    MembersComponent, // 追加
    MemberDetailComponent,
  ],
  bootstrap:    [
    AppComponent  // AppComponentに戻しておく
  ],
  providers: [
    MemberService
  ]
})
export class AppModule { }

実行結果。
トップページが非常にシンプルなものに。
f:id:noinoi_monstS4l:20190605004623p:plain

リンクをクリックすると,社員一覧が表示される。
URLにもパスが加えられ,ルーティングが正しく動作している。
また,社員をクリックした場合の詳細画面を表示させるイベントも据え置き。
f:id:noinoi_monstS4l:20190605004811p:plain

以上。