Angular Webアプリ開発入門17

はじめに

画面遷移では、「一覧をクリックすると、その詳細情報が表示される」というように、「主たるデータページ」から「その詳細ページ」に遷移する方式のものもある。こうした構成をとるものを「マスター/ディテイルアプリ(master-detail application)」という。マスター/ディテイルアプリでは「主たるページ」→「詳細ページ」の遷移、詳細ページ側に「元に戻る」などのリンクをつけておき、そこから戻れるようにするなどできる。
今回はレシピ検索システムを作成する。

 

新しいプロジェクトを作る

1. 新しいプロジェクトを作る
ng new cookbook

2. 一覧ページ
ng g c recip-list

3. 詳細ページ
ng g c recipe-data

4. RoutiongModuleを構成する
ng g module app-routing –flat –module=app

全面にコンポーネントを表示する

app.component.html

<router-outlet></router-outlet>

主たるページへのリダイレクトとURLパスのマッピング

 

1.インポート

app-routing.module.ts

import {Routes,RouterModule }from‘@angular/router’;

import {RecipeListComponent }from‘./recipe-list/recipe-list.component’;

 

2.リダイレクトとURLパスのマッピング設定

RouterModule.forRoot([

{path:“”,redirectTo:‘/recipe-list’,pathMatch:‘full’},

{path:“recipe-list”,component:RecipeListComponent},

])

 

設定したRouterModuleをエクスポートする。

exports:[

RouterModule

],

app-routing.module.ts

import {NgModule }from‘@angular/core’;

import {CommonModule }from‘@angular/common’;

import {Routes,RouterModule }from‘@angular/router’;

import {RecipeListComponent }from‘./recipe-list/recipe-list.component’;

const routes:Routes = [];

@NgModule({

imports: [

CommonModule,

RouterModule.forRoot([

{path:“”,redirectTo:‘/recipe-list’,pathMatch:‘full’},

{path:“recipe-list”,component:RecipeListComponent},

])

],

exports:[

RouterModule

],

declarations: [

]

})

export classAppRoutingModule { }

データ構造を作る

データ構造を定義する

項目名

意味

id

ID番号連番

name

名称

minute

所要時間

feature

キャッチコピー

1. recipeフォルダを作る
2. recipe.tsファイルを作る

export classRecipe {

id:number;

name:string;

minute:number;

feature:string;

}

データを定義する

1. recipe.data.tsファイルを作る
2. recipe.data.tsファイルを入力する

import {Recipe }from‘./recipe’;

exportconstRECIPEDATA:Recipe[] = [

{

id:1,

name:チキンライス,

minute:15,

feature:残りご飯で手早く。酸っぱいケチャップが鶏肉によく合う

},

{

id:2,

name:カレーライス,

minute:60,

feature:またカレーライス、やっぱりカレーライス。

},

{

id:3,

name:炊き込みご飯,

minute:60,

feature:実質作業時間は切る時間のみ

},

{

id:4,

name:ツナピラフ,

minute:60,

feature:もっとも簡単な「魚料理」

},

{

id:5,

name:チャーハン,

minute:15,

feature:簡単であっさり

},

]

 

一覧ページを作る

以上でレシピの一覧を扱うデータができ、RECIPEDATAという名前が参照できるようになった。

一覧ページでこのデータ一覧を参照し、画面に表示してみる。一覧ページの基本的な考え方は、*ngForを使ったループによる表示である。RecipeListConponentのプログラムにて、RECIPEDATAを参照し、自身のプロパティとして公開する。

TypeScriptプログラムの修正

import {Component,OnInit }from‘@angular/core’;

import { RECIPEDATA } from ‘../recipe/recipedata’;

@Component({

selector: ‘app-recipe-list’,

templateUrl: ‘./recipe-list.component.html’,

styleUrls: [‘./recipe-list.component.css’]

})

export classRecipeListComponentimplementsOnInit {

recipedata = RECIPEDATA;

constructor() { }

ngOnInit() {

}

}

 

テンプレートの修正

<h2>レシピ検索システム</h2>

<ul>

<li*ngFor=“let recipe of recipedata”>

{{recipe.name}}

</li>

</ul>

 

詳細ページを作る

どの詳細ページなのかをURLで定める

import {Recipe }from‘./recipe’;

exportconstRECIPEDATA:Recipe[] = [

{

id:1,

name:チキンライス,

minute:15,

feature:残りご飯で手早く。酸っぱいケチャップが鶏肉によく合う

},

{

id:2,

name:カレーライス,

minute:60,

feature:またカレーライス、やっぱりカレーライス。

},

{

id:3,

name:炊き込みご飯,

minute:60,

feature:実質作業時間は切る時間のみ

},

{

id:4,

name:ツナピラフ,

minute:60,

feature:もっとも簡単な「魚料理」

},

{

id:5,

name:チャーハン,

minute:15,

feature:簡単であっさり

},

]

 

このid値を使って「idが1番の時はチキンライス」というように区別するようにする。

パスにパラメータを渡す

1.idの部分が存在しないマッピングに対しは機能しない
「/recipe-data」のように「:id」の部分が省略された場合、このマッピングは機能しない。
2. idの書式は任意
「id」は書式が指定されているわけではないので、「/recipe-data/abcdsd」のように数値ではないものを渡された時も有効である。

import {NgModule }from‘@angular/core’;

import {CommonModule }from‘@angular/common’;

import {Routes,RouterModule }from‘@angular/router’;

import { RecipeListComponent } from ‘./recipe-list/recipe-list.component’;

import { RecipeDataComponent } from ‘./recipe-data/recipe-data.component’;

const routes:Routes = [];

@NgModule({

imports: [

CommonModule,

RouterModule.forRoot([

{path:””,redirectTo: ‘/recipe-list’, pathMatch: ‘full’},

{path:”recipe-list”, component:RecipeListComponent},

{path:”recipe-data/:id”, component:RecipeDataComponent}

])

],

exports:[

RouterModule

],

declarations: [

]

})

export classAppRoutingModule { }

 

パスに渡された値を読み取る

recipe-data.components.ts

import {Component,OnInit }from‘@angular/core’;

import { ActivatedRoute } from ‘@angular/router’;

@Component({

selector: ‘app-recipe-data’,

templateUrl: ‘./recipe-data.component.html’,

styleUrls: [‘./recipe-data.component.css’]

})

export classRecipeDataComponentimplementsOnInit {

recipeid:string;

constructor(private route:ActivatedRoute) { }

ngOnInit() {

this.recipeid= this.route.snapshot.paramMap.get(‘id’);

}

}

 

1. ActivatedRouteクラスのインポートと注入
現在ユーザーが表示しているURLや、そこに含まれているパラメータなどを参照するには、ActivatedRouteオ
ブジェクトを使う。
まず下記にようにActivatedRouteクラスをインポートする
import { ActivatedRoute } from ‘@angular/router’;

そして、コンストラクタでActivatedRouteクラスを注入する。下記のようにすると参照できるようになる。

2. パスに含まれている値の取得
recipeid:string;

実際にid値の部分を取得するには次のように記述する。
this.recipeid= this.route.snapshot.paramMap.get(‘id’);

 

受け取った値を表示する

recipe-data.component.html

<div>

{{recipeid}}番目のレシピが選択された。

</div>

 

一覧ページと詳細ページをリンクする

一覧リンクから詳細ページへのリンク

<h2>レシピ検索システム</h2>

<ul>

<li*ngFor=“let recipe of recipedata”>

<arouterLink=“/recipe-data/{{recipe.id}}”>{{recipe.name}}</a>

</li>

</ul>

 

元のページに戻れるようにする

import {Component,OnInit }from‘@angular/core’;

import {ActivatedRoute }from‘@angular/router’;

import { Location } from ‘@angular/common’;

@Component({

selector: ‘app-recipe-data’,

templateUrl: ‘./recipe-data.component.html’,

styleUrls: [‘./recipe-data.component.css’]

})

export classRecipeDataComponentimplementsOnInit {

recipeid:string;

constructor(privateroute:ActivatedRoute,private location:Location) { }

ngOnInit() {

this.recipeid=this.route.snapshot.paramMap.get(‘id’);

}

backToList() {

this.location.back();

}

}

 

リストに戻るボタンを追加する

<div>

{{recipeid}}番目のレシピが選択されました。

</div>

<button(click)=“backToList()”>リストに戻る</button>

 

詳細ページに画像などを表示する

いまはURLのうしろに指定したid値、つまり「/recipe-data/1」なら「1」という値しかテンプレートから参照できないので、これを「1」が指定されているのであれば、「1番目」のデータすなわち、

{

id: 1,

name:チキンライス,

minute: 15,

feature: 残りご飯で手早く。酸っぱいケチャップが鶏肉によく合う

},

 

という全体をテンプレートから参照できるようにする。

RECIPEDATAという定数で定義しているのため、この処理は「RECIPEDATAで管理されているデータのなかからidの値が1のものを探す」という操作になる。

このような「データを探す」という操作するには、findというメソッドを使う。具体的には次のようにすると、idが1番目

のRecipeオブジェクトできる。

 

RECIPEDATA.find(recipe=>recipe.id==1);

 

括弧のなかに指定しているのが、検索の条件式である。ここではRECIPEDATAという配列を「recipe」という名前で取り出し、その「idプロパティが1に合致する」という意味。もし該当するものが見つからなかったら、null値が得られる。

 

 

以上を踏まえ、RecipeとRECIPEDATAをインポートする

 

import {Component,OnInit }from‘@angular/core’;

import {ActivatedRoute }from‘@angular/router’;

import {Location }from‘@angular/common’;

import { Recipe } from ‘../recipe/recipe’;

import { RECIPEDATA } from ‘../recipe/recipedata’;

@Component({

selector: ‘app-recipe-data’,

templateUrl: ‘./recipe-data.component.html’,

styleUrls: [‘./recipe-data.component.css’]

})

export classRecipeDataComponentimplementsOnInit {

recipeid:string;

recipe:Recipe;

constructor(privateroute:ActivatedRoute,privatelocation:Location) { }

ngOnInit() {

this.recipeid=this.route.snapshot.paramMap.get(‘id’);

this.recipe = RECIPEDATA.find(recipe=>this.recipeid.toString()==this.recipeid);

}

backToList() {

this.location.back();

}

}

画像を配置する

これで、テンプレートからrecipeプロパティを参照することで、選択されたレシピの詳細情報を取得できる。例えば「{{recipe.name}}」と記入すればレシピの名前をがキャッチコピーとして表示できる。
問題となるのは画像だが、ここではid番号と関連づけ、idが1の時は「pic1.png1」のようにする。
Angularは画像やHTML、その他コンテンツファイルはassetsというフォルダに置くのが慣例である。
ここではassetsフォルダの下にimgフォルダを作り、その中に各種レシピの画像をおく。

**レシピ詳細**

<div*ngIf=“recipe”>

<h2>{{recipe.name}}</h2>

<p>{{recipe.feature}}</p>

<table>

<tr>

<td>

<imgwidth=“200”src=“/assets/img/pict{{recipeid}}.png”>

</td>

<td>

<b>調理時間:</b>{{recipe.minute}}<br><br>

</td>

</tr>

</table>

</div>

<button(click)=“backToList()”>リストに戻る</button>

 

終わりに

今回はページ遷移の方法について学んだ。

1. RoutingModuleを使ったURLパスとコンポーネントとのマッピング
ページを遷移するには、RoutingModuleを使って、URLパスとコンポーネントをマッピングする

2. コンポーネントの表示
コンポーネントを表示したいところは「<router-outlet></router-outlet>」と記述する。

3. URLでパラメータを渡す
マスター/ディティールアプリケーションを構成する場合など、詳細ページにパラメータを渡したい時は、RouterModuleで構成するパス名に「:パラメータ名」(例えばid)と記述する。
その値はActivatedRoureオブジェクトの「.snapshot.paramMap.get(‘パラメータ名’)」として取得できる。

 

コメント