[超初心者が行く]ルーティング編 Angular5 Tutorialしてみた7

Angular5 Tutorial ルーティング!

Angular – Tutorial: Tour of Heroes を翻訳(意訳多め)しています。

[超初心者が行く] Angular5 Tutorialしてみた6の続き

前回は、サービスを使って非同期のデータ受け渡し機能を構築しました。

さて、今回はルーティングを使って各項目をそれぞれ別々のページに遷移させましょう!

ここからが翻訳になります。

ビックリマークの部分は個人的にわからない用語の意味を載せています。
本家Angularのサイトだけではわからない部分が多いため、本家以外の説明も載せているため、どこからどこまでが本家の情報なのか線引ができなくなっています。ご了承ください。

では、チュートリアルやっていきましょう!

ルーティング

ヒーローズツアーアプリに新しい機能を追加します:

  • ダッシュボードビューを追加します。
  • HeroesビューとDashboardビューの間を遷移する機能を追加します。
  • いずれかのビューでユーザーがヒーロー名をクリックすると、選択したヒーローの詳細ビューに移動します。
  • ユーザーがディープリンクをクリックすると、特定のヒーローの詳細ビューが開きます。

完了したら、ユーザーは次のようにアプリをナビゲートできます:

View navigations

AppRoutingModuleを追加する

Angularでのベストプラクティスは、最上位モジュールAppModuleにルーティング専用モジュールとして、インポートし、ルータを読み込み、設定することです。

Angularではルーターのモジュールクラス名はAppRoutingModuleであり、src / appフォルダのapp-routing.module.tsに属します。

CLIを使用して生成します。

ng generate module app-routing –flat –module=app
  • –flatは、src / appにファイルを置きます。
  • –module = appは、AppModuleのインポート配列にそのモジュールを登録するようにCLIに指示します。
  • 追加されない場合は次のコードを追加します。
    import { AppRoutingModule } from ‘./app-routing.module’;

生成されるファイルは次のようになります。

src/app/app-routing.module.ts (generated)

一般的には、ルーティングモジュールにコンポーネントを宣言しないので、@NgModule内の@NgModule.declarations配列とCommonModule参照を削除することもできます。

また、RouterModule内のRouteでルータを設定するため、@Angular/Routerライブラリからこれら2つのシンボルをインポートします。

そして、@NgModule.exports配列にRouterModuleを追加します。 RouterModuleをエクスポートすると、ルータディレクティブを必要とするAppModuleコンポーネントで使用できるようになります。

AppRoutingModuleは次のようになります:

src/app/app-routing.module.ts (v1)
ルートを追加する

ルートは、ユーザーがリンクをクリックするか、URLをブラウザのアドレスバーに貼り付けるときに、どのビューを表示するかをルーターに指示します。

典型的なAngularルートは2つの特性を有する:

  1. パス:ブラウザのアドレスバーのURL
  2. コンポーネント:このルートにナビゲートするときにルータが作成するコンポーネント

URLがlocalhost:4200/heroesであれば、HeroesComponentに移動します。

HeroesComponentをインポートしてルートで参照できるようにします。 次に、そのコンポーネントへの単一のルートを持つルート配列を定義します。

import { HeroesComponent } from ‘./heroes/heroes.component’;

const routes: Routes = [
{ path: ‘heroes’, component: HeroesComponent }
];

設定が完了すると、ルータはそのURLを「heroes」のパスに一致させ、HeroesComponentを表示します。
RouterModule.forRoot()

まず、最初にルータを初期化し、そしてULRパスの変更を設定します。

RouterModuleを@NgModule.imports配列に追加し、imports配列内のRouterModule.forRoot()を次のように呼び出し、このステップでルートを設定します。

imports: [ RouterModule.forRoot(routes) ],

このメソッドは、アプリケーションのルートレベルでルーターを構成するため、forRoot()と呼ばれます。 forRoot()メソッドは、ルーティングに必要なサービスプロバイダとディレクティブを提供し、現在のブラウザのURLに基づいて初期ナビゲーションを実行します。

RouterOutletを追加

AppComponentテンプレートを開き<app-heroes>要素を<router-outlet>要素で置き換えます。

src/app/app.component.html (router-outlet)

<app-heroes>を削除したのは、ユーザーがHeroesComponentをナビゲートしたときにのみHeroesComponentを表示するためです。

<router-outlet>は、ルーテッドビューをどこに表示するかをルータに通知します。

RouterOutletは、RouterModuleをエクスポートしたAppRoutingModuleをAppModuleがインポートするため、AppComponentで使用可能になったルータのディレクティブです。

試してみよう!

このCLIコマンドを使用して実行してみましょう。

ng serve

ブラウザは、ヒーローのリストではなく、アプリのタイトルのみ表示されているでしょう。

ブラウザのアドレスバーを見てください。 URLはhttp://localhost:4200/になっています。 HeroesComponentへのルートパスはhttp://localhost:4200/heroesです。

ブラウザのアドレスバーにあるURLに/heroesを追加します。 すると、ヒーローマスター/ディテールビューが表示されます。

ナビゲーションリンクを追加する(routerLink)

ユーザーが、ページ遷移しやすいようにナビゲートリンクを追加しましょう。

<nav>要素を追加し、その中に、クリックするとHeroesComponentへナビゲーションをトリガーするアンカー要素を追加します。 修正されたAppComponentテンプレートは次のようになります。

src/app/app.component.html (heroes RouterLink)

routerLink属性は、 “/heroes”を設定します。これは、HeroesComponentへのルートと一致する文字列です。 routerLinkは、ユーザのクリックをルータのナビゲーションに変えるRouterLinkディレクティブのセレクタです。 これは、RouterModuleのパブリックディレクティブの別のものです。

ブラウザが更新され、アプリのタイトルとヒーローのリンクが表示されますが、ヒーローのリストは表示されません。

リンクをクリックします。 アドレスバーが/heroesに更新され、ヒーローのリストが表示されます。

プライベートCSSスタイルをapp.component.cssに追加することで、このナビゲーションリンクと今後のナビゲーションリンクをさらに見栄えのよいものにすることができます。

app.component.css

ダッシュボードビューを追加する

ルーティングは、複数のビューがある場合にはより意味があります。 これまでのところ、ヒーローだけのビューでした。ここから幾つか追加していきます。まずはダッシュボードを追加します。

CLIを使用してDashboardComponentを追加します。

コマンド ng generate component dashboard

CLIは、DashboardComponentのファイルを生成し、AppModuleで宣言します。

これらの3つのファイルのデフォルトのファイル内容を次のように置き換えます。

src/app/dashboard/dashboard.component.html

src/app/dashboard/dashboard.component.ts

src/app/dashboard/dashboard.component.css

テンプレートにはヒーロー名リンクのグリッドが表示されます。

  • *ngForリピーターは、コンポーネントのヒーロー配列と同じ数のリンクを作成します。
  • リンクは、dashboard.component.cssによって色付きのブロックとしてスタイル設定されています。
  • リンクはまだありませんが、まもなく追加されます。

クラスは、HeroesComponentクラスに似ています。

  • ヒーロー配列プロパティを定義します。
  • コンストラクタは、AngularがHeroServiceをプライベートheroServiceプロパティに注入することを期待しています。
  • ngOnInit()ライフサイクルフックはgetHeroesを呼び出します。

次のgetHeroesは、表示されるヒーローの数を4(配列の2-5)に減らします。

getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}

ダッシュボードルートを追加する

ダッシュボードにナビゲートするには、ルータに適切なルートが必要です。

AppRoutingModuleでDashboardComponentをインポートします。

import { DashboardComponent } from ‘./dashboard/dashboard.component’;

さらに、AppRoutingModule.routes配列に、DashboardComponentのパスに一致するルートを追加します。

{ path: ‘dashboard’, component: DashboardComponent },
src/app/app-routing.module.ts (import DashboardComponent)

デフォルトルートを追加する

アプリが起動時の、ブラウザのアドレスバーはWebサイトのルートを指します。 今は、既存のルートが設定されていないため、ルータはどこへも移動しません。

アプリをダッシュボードに自動的にナビゲートするには、AppRoutingModule.Routes配列に次のルートを追加します。

{ path: ”, redirectTo: ‘/dashboard’, pathMatch: ‘full’ },

このルートは、空のパスと完全に一致するURLが ‘/dashboard’であるルートにリダイレクトします。

ブラウザが更新されると、ルーターはDashboardComponentをロードし、ブラウザのアドレスバーには/ダッシュボードのURLが表示されます。

シェルにダッシュボードリンクを追加する

ユーザーは、ページ上部にあるナビゲーション領域のリンクをクリックすることで、DashboardComponentとHeroesComponentの間を行きできるようにします。

Heroesリンクのすぐ上に、AppComponentシェルテンプレートへのダッシュボードナビゲーションリンクを追加します。

src/app/app.component.html

ブラウザが更新されたら、リンクをクリックして2つのビュー間を自由にナビゲートできます。

ヒーローの詳細へのナビゲート

HeroDetailsComponentは、選択されたヒーローの詳細を表示します。 現時点では、HeroDetailsComponentはHeroesComponentの下部にのみ表示されます

ユーザーは3つの方法でこれらの詳細にアクセスしたいと思うでしょう。

  • ダッシュボードでヒーローをクリック
  • ヒーローリストのヒーローをクリック
  • ブラウザのアドレスバーに特定のヒーローの「ディープリンク」URLを貼り付け

このセクションでは、HeroDetailsComponentへのナビゲーションを有効にし、HeroesComponentから分離します。

HeroesComponentからヒーローの詳細を削除する

ユーザーがHeroesComponentのヒーローアイテムをクリックすると、アプリケーションはHeroDetailComponentに移動し、ヒーローリストビューをヒーロー詳細ビューに置き換えます。 ヒーローリストビューは、今のようにヒーローの詳細を表示しないようにします。

HeroesComponentテンプレート(heroes / heroes.component.html)を開き、下から<app-hero-detail>要素を削除します。

heroes.component.html


まだ、ヒーローアイテムをクリックしても、何も起きません。 HeroDetailComponentへのルーティングを有効にした直後に修正します。

ヒーローの詳細ルートを追加する

./detail/11のようなURLは、idが11のヒーローのHero Detailビューにナビゲートするための適切なURLになります。

AppRoutingModuleを開き、HeroDetailComponentをインポートします。

import { HeroDetailComponent } from ‘./hero-detail/hero-detail.component’;

次に、パスパターンをヒーロー詳細ビューに一致させるため、パラメータ化されたルートをAppRoutingModule.routes配列に追加します。

{ path: ‘detail/:id’, component: HeroDetailComponent },

パスのコロン(:)は、次のことを示します。idは、特定のヒーローIDのプレースホルダです。

この時点で、すべてのアプリケーションルートが配置されたことになります。

src/app/app-routing.module.ts (all routes)

DashboardComponentヒーローリンク

DashboardComponentのヒーローリンクは現時点でパーマリンクを生成していません。

ルータにHeroDetailComponentへのルートがあるので、ダッシュボードのヒーローリンクを修正して、パラメータ化されたダッシュボードルート経由でナビゲートします。

src/app/dashboard/dashboard.component.html (hero links)

*ngForリピータ内でAngular補間バインディングを使用して、現在のインターアクションのhero.idを各routerLinkに挿入しています。

HeroesComponentのヒーローリンク

現在、HeroesComponentのヒーローアイテムは、クリックイベントをコンポーネントのonSelect()メソッドにバインドされている<li>要素です。

<li>を*ngForのみとして、アンカー要素<a>でバッジと名前を囲み、ダッシュボードテンプレートと同じアンカーにrouterLink属性を追加するように変更します。

src/app/heroes/heroes.component.html (list with links)


以前と同じようにリストを見やすくするためにプライベートスタイルシート(heroes.component.css)を修正する必要があります。

heroes.component.css

デッドコードを削除する(オプション)

HeroesComponentクラスは引き続き動作しますが、onSelect()メソッドとselectedHeroプロパティは使用されなくなりました。

きちんと整理しましょう。 デッドコードを整理した後のクラスは次のようになります。

src/app/heroes/heroes.component.ts (cleaned up)

ルーティング可能なHeroDetailComponent

以前は、親HeroesComponentがHeroDetailComponent.heroプロパティを設定し、HeroDetailComponentがヒーローを表示していました。

HeroesComponentでは設定の機能がなくなりました。ルータは./detail/11のようなURLに応答してHeroDetailComponentを作成することにします。

そのため、HeroDetailComponentは、ヒーローを表示するための新しい方法が必要です。

作成したルート(URL)を取得し、ルートからIDを抽出する。そして、HeroService経由でサーバーからそのIDを持つヒーローを取得するようにしましょう。

次のインポートを追加します。

import { ActivatedRoute } from ‘@angular/router’;
import { Location } from ‘@angular/common’;import { HeroService } from ‘../hero.service’;

ActivatedRoute、HeroService、およびLocationサービスをコンストラクタに挿入し、その値をプライベートフィールドに保存します。

constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) {}
 src/app/hero-detail/hero-detail.component.ts

ActivatedRouteは、HeroDetailComponentのこのインスタンスへのルートに関する情報を保持します。 このコンポーネントは、URLから抽出されたルートのパラメータバッグが必要なためActivatedRouteを使います。ルートの”id”パラメータは、表示するヒーローのIDです。

HeroServiceはリモートサーバーからヒーローデータを取得し、このコンポーネントはそれを使用してヒーローを表示します。

ロケーションは、ブラウザと対話するためのAngularサービスです。 あとで、「BACK」ナビゲートを使用してダッシュボードに戻るリンクを作ります。

idルートパラメータを抽出する

ngOnInit()ライフサイクルフックでgetHero()を呼び出し、以下のように定義します。

src/app/hero-detail/hero-detail.component.ts

route.snapshotは、コンポーネントの作成直後のルート情報の静的イメージです。

paramMapは、URLから抽出されたルートパラメータ値の引数を設定します。 “id”キーは、取り出すヒーローのIDを返します。

ルートパラメータは常に文字列です。 JavaScript(+)演算子は文字列を数値に変換します。これは主人公のIDでなければなりません。

ブラウザがリフレッシュされ、コンパイラエラーでアプリケーションがクラッシュします。 HeroServiceにはgetHero()メソッドがありません。 今すぐ追加してください。

HeroService.getHero()を追加します

HeroServiceを開き、このgetHero()メソッドを追加します。

idを埋め込むためのJavaScriptテンプレートリテラルを定義するバッククォート( `)に注意してください。

getHeroes()と同様に、getHero()には非同期のサインがあります。 RxJS of()関数を使ってObservableとしてサンプルヒーローを返します。

getHero()を呼び出すHeroDetailComponentを変更することなく、実際のHTTPリクエストとしてgetHero()を再実装することができます。

試してみよう!

ブラウザがリフレッシュされ、アプリは再び動作します。 ダッシュボードまたはヒーローリストでヒーローをクリックし、そのヒーローの詳細ビューに移動することができます。

ブラウザのアドレスバーにlocalhost:4200/detail/11を貼り付けると、ルータはid:11、 “Mr. Nice”のヒーローの詳細ビューにナビゲートします。

ルートを探す

ブラウザの戻るボタンをクリックすると、詳細ビューへ進んだURLに応じてヒーローリストまたはダッシュボードビューに戻ることができます。

これを行うことができるHeroDetailビューのボタンを用意しておくといいでしょう。

戻るボタンをコンポーネントテンプレートの下部に追加し、コンポーネントのgoBack()メソッドにバインドします。

src/app/hero-detail/hero-detail.component.html (back button)

ロケーションサービスを使用して、ブラウザのヒストリスタックの1ステップ前にナビゲートするコンポーネントクラスとしてgoBack()メソッドを追加します。

src/app/hero-detail/hero-detail.component.ts (goBack)

ブラウザを更新して、試してみてください。 ユーザーは、ダッシュボードからヒーローの詳細へ、そしてヒーローリストからヒーローの詳細へ、ヒーローの詳細からヒーローに戻ったりと、アプリの周りをナビゲートできるようになりました。

このページを推奨ナビゲーション要件を満たすことになります。

最終的なコードレビュー

このページで解説されているコードファイルは次のとおりです。アプリはこのライブサンプル/ダウンロードの例のようになります。

AppRoutingModule and AppModule
src/app/app-routing.module.ts

src/app/app.module.ts

AppComponent
src/app/app.component.html

src/app/app.component.css

DashboardComponent
src/app/dashboard/dashboard.component.html

src/app/dashboard/dashboard.component.ts

src/app/dashboard/dashboard.component.css

HeroesComponent
src/app/heroes/heroes.component.html

src/app/heroes/heroes.component.ts

src/app/heroes/heroes.component.css

HeroDetailComponent
src/app/hero-detail/hero-detail.component.html

src/app/hero-detail/hero-detail.component.ts

src/app/hero-detail/hero-detail.component.css

まとめ

  • コンポーネント間を移動するためにAngularルータを追加しました。
  • AppComponentテンプレートを<a>リンクを持つナビゲーションシェルに変換、<router-outlet>の追加を行いました。
  • AppRoutingModuleでルータを設定しました。
  • 単純なルート、リダイレクトルート、およびパラメータ化されたルートを定義しました。
  • アンカー要素でrouterLinkディレクティブを使用しました。
  • 密接に結合していたルーテッド詳細ビューのマスター/詳細ビューをにリファクタリングしました。
  • ルータリンクパラメータを使用して、ユーザが選択したヒーローの詳細ビューに移動しました。
  • 複数のコンポーネント間でHeroServiceを共有しました。

次回はチュートリアルラスト!!!

今回は、ルーティングをしました。

これまで作ってきたコンポーネントをそれぞれのURLに割り当てて、ナビゲーションできるようにルートを設定しました。

ようやくWEBサイトっぽくなってきましたね。

その分、複雑さもましていますが・・・

さて、次回はチュートリアル最後!

今、サンプルヒーローデータを使っていますが、おそらくようやくサーバー上のデータをやり取りできることになると思います。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする