Angular Webアプリ開発入門19

はじめに

前回の続きで、今回は項目を増やす。そのため、データモデルであるRecipeクラスを修正する。
これまで、「id」「name」「miniute」「feature」の4項目だったが、「manner」「serve」「ingre」の3つの項目を加える。また、今回は検索機能も追加する。
レシピのようなデータ構造を正確に検索するのは大変であるが、簡易的なもので良いのであれば、オブジェクトをJSON文字列に変換してします方法が簡単である。JSON文字列にすると、どのようなオブジェクトであれ、「{プロパティ:値、プロパティ:値・・・}」のように文字列になる。この文字列に対して、「検索したいものが含まれているかどうか」を検索すれば、簡易的に検索を実現できる。

 

追加するレシピ項目

項目名

意味

manner

「和」「洋」「中」

serve

何人分か

ingre

材料。配列として構成する

name

材料名

amount

分量

このような構造にする。

import {ArgumentOutOfRangeError }from“rxjs”;

export classRecipe {

id:number;

name:string;

minute:number;

feature:string;

manner: string;

serve: number;

ingre: {

name:string,

amount:string

}[];

一覧ページで表形式で表示する

レシピの詳細情報が増えたため、一覧では料理のな目だけでなく、「キャッチコピー」「調理時間」「主な材料」も表示できるようにする。

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

<table>

<tr><th>名前</th><th>所要時間</th><th>一言</th><th>主な材料</th></tr>

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

<td>

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

</td>

<td>{{recipe.minute}}</td>

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

<td>

<span*ngFor=“let item of recipe.ingre; let i=index”>{{item.name}}&nbsp;</span>

</td>

</tr>

</table>

一部の材料だけ表示する

横幅が長くて見づらいので、材料を先頭3つだけ表示するようにする。
そのため、recipe.ingreを取得して、*ngForを繰り返し表示しているところで、表示回数をカウントし、「3つ以上になったら表示しなし」というようにする。

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

<table>

<tr><th>名前</th><th>所要時間</th><th>一言</th><th>主な材料</th></tr>

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

<td>

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

</td>

<td>{{recipe.minute}}</td>

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

<td>

<span*ngFor=“let item of recipe.ingre; let i=index”>

<ng-container *ngIf=”i<3″>{{item.name}}&nbsp;</ng-container></span>

</td>

</tr>

</table>

詳細ページを修正する

**レシピ詳細**

<div*ngIf=“recipe”>

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

<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>

<b>材料 ({{recipe.serve}}人分) :</b>

<ul>

<li *ngFor=”let item of recipe.ingre”>

{{item.name}}&nbsp;{{item.amount}}

</li>

</ul>

</td>

</tr>

</table>

</div>

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

検索機能を作る JSONデータにして文字列として比較する

レシピのようなデータ構造を正確に検索するのは大変であるが、簡易的なもので良いのであれば、オブジェクトをJSON文字列に変換してします方法が簡単である。JSON文字列にすると、どのようなオブジェクトであれ、「{プロパティ:値、プロパティ:値・・・}」のように文字列になる。この文字列に対して、「検索したいものが含まれているかどうか」を検索すれば、簡易的に検索を実現できる。

検索機能を実装する

①テキストボックスと検索洋のボタンを用意する
一覧ページにテキストボックスと検索用のボタンを用意する。ボタンがクリックされたら、コンポーネントの検索用のメソッドが実行されるように構成する。

このメソッドは、②で実装するもので、serchRecipeというメソッド名とする。このメソッドには、入力されたテキストを渡す。


②検索機能を実装する
コンポーネントにserchRecipeというメソッドというメソッドを実装し、①から実行可能なようにし、そこに、検索機能を実装する。検索機能はこのserchRecipeに実装するのではなく、サービスであるRecipeServiceの方に実装し、それを間接的に事項するものとする。

検索結果は、コンポーネントのrecipeプロパティに設定する。テンプレートでは、このレシピプロパティの値を見て表として表示しているため、recipeプロパティの値を変更すればそれに伴い、表示されている表も変わる。

テンプレートに検索用のテキストボックスとボタンをつける

**レシピ詳細**

検索:

<input #keyword size = “20” />

<button (click)=”serchRecipe(keyword.value)”>Serch</button>

<div*ngIf=“recipe”>

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

<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>

<b>材料 ({{recipe.serve}}人分) :</b>

<ul>

<li*ngFor=“let item of recipe.ingre”>

{{item.name}}&nbsp;{{item.amount}}

</li>

</ul>

</td>

</tr>

</table>

</div>

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

検索機能をつける

recipe.service.ts

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

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

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

@Injectable({

providedIn: ‘root’

})

export classRecipeService {

recipedata:Recipe[]=RECIPEDATA;

constructor() { }

getRecipedata():Recipe[]{

return this.recipedata;

}

getRecipe(id:string):Recipe{

return this.recipedata.find(recipe=>recipe.id.toString()==id);

}

serachRecipe(keyword: string): Recipe[] {

let resultArr: Recipe[] = [];

for (let recipe of this.recipedata) {

let dataStr = JSON.stringify(recipe);

if (dataStr.search(keyword) >= 0) {

resultArr.push(recipe);

}

}

return resultArr;

}

}

コンポーネント側から検索機能を実装する

いま作成した検索機能を実行して、キーワードに合致したものだけをコンポーネント側に実装していく。

recipe-list.component.ts

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

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

import {RecipeService }from‘../recipe.service’;

@Component({

selector: ‘app-recipe-list’,

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

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

})

export classRecipeListComponentimplementsOnInit {

recipedata:Recipe[];

constructor(privatersv:RecipeService) { }

ngOnInit() {

this.recipedata =this.rsv.getRecipedata();

}

searchRecipe(keyword:string){

this.recipedata = this.rsv.serachRecipe(keyword);

}

}

終わりに

①サービスオブジェクトを導入する
データ管理するためには、サービスオブジェクトを作る。そのサービスオブジェクトに検索などのメソッドを実装して、コンポーネントから呼び出すことで検索機能を実装する。

②<ng-container>で要素なしの出力になる
要素なしで繰り返しの出力をしたいときは、*ngForsでループのときに<ng-container>を使う。

③ループのインデックス
*ngForを使って処理するときにindexを指定すると、ループ回数を取得できます。

<span *ngFor=”let item of recipe.ingre; let i=index”>
<ng-container *ngIf=”i<3″>{{item.name}}&nbsp;</ng-container></span>

これまででAngularのプログラミングの話は終わる。
最後に作成したアプリケーションをインターネットのレンタルサーバーに乗せるときにどのようにしなればならないかを学ぶ。

一覧ページと詳細ページともに、RecipeServiceを経由してデータを取得できるようになった。
次回はレシピデータを増やし、レシピの項目を増やす。

 

コメント