ionicでアプリ開発入門 リスト表示を理解しよう -ion-list-

ionicでアプリ開発入門 リスト表示を理解しよう -ion-list-

チュートリアルでの解説もあと少しで終わりそうです。
このページでデータ表示、受け渡しに軽く触れてサクッとアプリでも作ってみたいところですね。

ではサクッとやっていきましょう。
今回はチュートリアルで作成されるページMy First Listです。

My First Listを見てみる。

My First Listを表示してみましょう。
MyFarstListのview
ずらっと一覧が表示され、タップすると詳細ページへ移動します。
このページを表示するファイルは
/src/page/list
listにすべて入っています。

データバインディングを覚える

このリストがどこで作られているかを説明する前に、タイトルを変更してみましょう。
タイトルを変更するにはlist.htmlの
<ion-title>My First List</ion-title>
を変更すれば簡単なのですが
今回は少し回りくどい変更の仕方を行います。

<ion-title>My First List</ion-title>
//My First Listを消して、二重括弧 {{変数名}}で囲む
<ion-title>{{mytitle}}</ion-title>

私の場合mytitleという変数名にしました。

ではlist.tsを開いて、
export class ListPage {の下の行に
mytitleの変数を設定します。


export class ListPage {
mytitle: string ="好きなタイトル"; //好きなタイトルを入れる
icons: string[];
items: Array<{title: string, note: string, icon: string}>;

mytitleという変数を設定:string(文字列の指定) =”タイトル名”;
となります。
これで保存するとlist.htmlで設定した{{mytitle}}がlist.tsで設定した変数の文字列に置き換わります。
これをバインディング、またはデータバインディングと言います。

データバインディングとは

データバインディングはコンポーネントにおいてテンプレートとクラス内の要素を繋ぐ仕組みです。

どういう事なのかと言うと
export classの中に設定した変数はhtmlファイルとtsファイル(コンパイル後にはjs)間でデータ(値)を共有することが可能になります。
その為list.tsで設定した文字列がhtmlに表示されます。
ちなみに、共有できるということはhtml側からも操作可能という事です。
たとえばformの値を変えるとts側の値も置き換わるなど。

list.thmlを調べる。

ではバインディングの説明も終わったところで
さらっとhtml側を見ていきましょう。

今回説明する箇所はこちらです。

<ion-content>
<ion-list>
<button ion-item *ngFor="let item of items" (click)="itemTapped($event, item)">
<ion-icon name="{{item.icon}}" item-left></ion-icon>
{{item.title}}
<div class="item-note" item-right>
{{item.note}}
</div>
</button>
</ion-list>
</ion-content>

<button ion-item *ngFor=”let item of items” (click)=”itemTapped($event, item)”>
これは前回やったngForのループですね。
*ngForの説明おさらい

ということは
<button ~~>から</button>までitemsの分繰り返されると見て良いでしょう。

<ion-icon name=”{{item.icon}}” item-left></ion-icon>
この記述はionicが提供するアイコンファイルを決めています。
name=の値で出力するアイコンを決めています。ループするのでここは入っている値次第で{{item.icon}}の中身が変わります。
更にitem-leftをつけることで左寄せにしています。

ionicのアイコンはこちらから見れます

{{item.title}}は、前回もやりましたがitemの中にtitleオブジェクトが入っているのでしょう。

<div class="item-note" item-right>
{{item.note}}
</div>

こちらに関してはdivタグで囲み、item-rightの属性をつけることで右寄せにしているようです。
その中に、item変数に入っているnoteの値を表示している。

これで全部説明が終わった気がします。
分かりやすいようにSS撮りました。
ループの説明図(タグ付き)

では、{{item.icon}}、{{item.title}}、{{item.note}}を頭に入れてlist.tsを見ていきましょう。

見るべきポイントはlist.ts

list.tsを開いて少しずつ見ていきましょう。

export class ListPage {
mytitle: string ="好きな名前(title)";
icons: string[];
items: Array<{title: string, note: string, icon: string}>;

まずは、icons: string[];
で、iconsを定義します。
items変数を定義して、中に入る型を決めます。
Array<{title: string, note: string, icon: string}>
title、note、iconすべて文字列で宣言してますね。

ではその下を追ってみます。

constructor(public navCtrl: NavController, public navParams: NavParams) {
this.icons = ['flask', 'wifi', 'beer', 'football', 'basketball',
'paper-plane','american-football', 'boat', 'bluetooth', 'build'];
this.items = [];
for(let i = 1; i < 11; i++) {
this.items.push({
title: 'Item ' + i,
note: 'This is item #' + i,
icon: this.icons[Math.floor(Math.random() * this.icons.length)]
});
}
}
constructorの下から見ていきましょう。
this.iconsに文字列をセット、合計10
これが<ion-icon>にセットされてブラウザに出力した時にアイコンに変換されます。
this.itemsをセットして、

for文を見ていきましょう。
for(let i = 1; i < 11; i++) {
for文はngForと同じ感じで繰り返しです。
letでiを定義、iの中に1を設定します。
i < 11で iが11より小さければループ i++で最後にiに1を追加

for(iを1にセット; iが11より小さければ{}の中を繰り返し、 最後にiに1を追加)
最初にiに1が入ってるので、1からカウントしていって、10まで繰り返します。11になったら < にはならないので10回繰り返した時点で終了です。

ではでは{}の中を見ていきますね。

this.items.push({
pushは末尾に追加すると言う処理なので、
itemsの末尾に追加していく、となります。
では何を追加するのか、更に{}の中を見ていきますね

title: ‘Item ‘ + i,
itemsのtitleにItemとforで定義したiの中身が入ります。
1回目の時iは1、5回目のループで5が入ります。
なので、8回目のループでtitleに入るのはItem8が入りますね。
htmlで表示される個所は{{item.title}}になります。

note: ‘This is item #’ + i,
こちらも同じ様にiの数字が入ります。
list.htmlの{{item.note}}の箇所に当ります。

icon: this.icons[Math.floor(Math.random() * this.icons.length)]
先にlist.htmlのどこかと言うと{{item.icon}}になります。
this.iconsに入るのですが、Math.floorからすべてjavascriptの記述ですね。
まずMath.floor

データバインディングとは

Mathオブジェクトのfloor()メソッドは、小数点以下を切り捨てます。

小数点以外を返すと言うことですね。
何の小数点かと言うと、
Math.random() * this.icons.length
この中身で、小数点を切り捨てたものを返します。

Math.random()は0以上1未満のランダムな数値を返す。
つまり、0.0~0.1 0.2 …..~ 1未満のランダムな数字を出力します
そして、*なので、掛け算

Math.random() …… 0以上1未満の疑似ランダムな数値を返す
そして、this.icons.lengthは

constructor(public navCtrl: NavController, public navParams: NavParams) {
this.icons = ['flask', 'wifi', 'beer', 'football', 'basketball', 'paper-plane',
'american-football', 'boat', 'bluetooth', 'build'];

ここのthis.iconsで設定した数を数えて出力しています。
flask, wifi, beer, football, basketball,
paper-plane, american-football, boat, bluetooth, build
iconsには10の文字列が入っています。
なので、this.icons.lengthには10が入ります。

計算式としては、
(Math.random 0~0.9 × 10)小数点切り捨て
になります。
これなら出てくる数字は0~9に限定されます。1は未満なので含みません。

ここで注意しなければいけないのは
this.icons.lengthでは単純に数えて10個有ると出力しますが
this.iconsの配列に入っているキーワードの呼び出しは1~10ではありません。
配列は0から計算します。
0番にflask 1番にwifi 2番にbeerが入っています。
まあここら辺は基本だよね。

更にthis.iconsの[何番目の数字]
と言う風に指定しているので
this.iconsでセットした0番目~9番目の文字列の中から該当する文字列をiconにセットします。

iconは何でも良いや、と言う人がいれば

icon: this.icons[0.9 * this.icons.length]

こうやって直接数字掛けるiconsの数でも良いし
もっと言えば
icon: this.icons[3]
と、具体的に数字を直接書いてやっても良いです。
この場合はiconにはiconsの3番に該当するfootballが入ります。
icon: football です。

なので上の様に直接指定した場合には全部がfootballのアイコンに染まります。

データを追加してみよう

では、itemのデータを追加してみましょう。
簡単です。
list.tsの
for文で何回ループするかを追加してやればいいだけです。
最初は
for(let i = 1; i < 11; i++) { で、11より小さければなので10回繰り返していました。 今回は15回繰り返してデータを作ってみましょう。 for(let i = 1; i < 16; i++) { これで15回ループするので for文の中のtitle、note、iconのデータも15回セットされます。 this.items の中には15のデータが入ることになります。

詳細ページの確認item-datelist

リスト一覧からどれでも良いのでタップすると、簡単なリストの詳細ページを開きます。
このページは
/src/page/item-datelist/
が該当します。

item-datelis.htmlから見ていきましょう。
と言っても特に見るところは無いですね、list.htmlのように
変数を受けとり表示しているだけです。
今回はループもなにも有りません。
唯一見るところと言えば、
{{selectedItem.title}}
selectedItemが変数名になっているんだな、と言うところでしょうか。

ではitem-datelis.tsを見ていきます。
短いので全部張り付けます。

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
@Component({
selector: 'page-item-details',
templateUrl: 'item-details.html'
})
export class ItemDetailsPage {
selectedItem: any;
constructor(public navCtrl: NavController, public navParams: NavParams) {
// If we navigated to this page, we will have an item available as a nav param
this.selectedItem = navParams.get('item');
}
}

コメントアウトにはこうかかれています。

If we navigated to this page, we will have an item available as a nav param
このページに移動した場合、navパラメータとして利用できる項目があります

さて、
@Componenでテンプレートを選んでるのでここはスルーして
selectedItem: any;で変数を決めているまでは良いですよね。
item-details.htmlにあった
selectedItem.titleが無いんですが…
でもページにitemが出ている。

データの受取

何が起きているかと言うと、item-detailsのページは
list.tsのリストデータからデータ(パラメーター)を受け取ってページを表示しています。
具体的には

  constructor(public navCtrl: NavController, public navParams: NavParams) {
// If we navigated to this page, we will have an item available as a nav param
this.selectedItem = navParams.get('item');
}

この部分になります。
this.selectedItemにnavParams.get(‘item’);を入れていますね。
navParamsってなんぞ

詳細はここに書いてます。
navParams
NavParamsは、ページ上に存在するオブジェクトであり、その特定のビューのデータを含むことができます。
わからないですね。

navParamsは別ページから送られたのパラメータの受け取りに使用します。
じゃあその機能はどれが提供してくれているの?と思いますよね。

ページ遷移はionic-angularが提供してくれる

navParamsでデータを受けってselectedItemに代入しているのはわかったけどnavParamsはどこで定義してるのか
ソースを見ればすぐわかると思います。

constructor(public navCtrl: NavController, public navParams: NavParams) {

この一文ですね。
意味合いは、NavParamsと言う機能をnavParamsと言う名前で使います。となるでしょうか。
public ソース上で使う名前 : 提供される正式な機能名

覚えにくければ自分で変えても良いですが、人が見てもわかる名前にしましょう。
極端に書けばこれでも動きます。

constructor(public navCtrl: NavController, public uketoriParams: NavParams) {

その際は下の行は
this.selectedItem = uketoriParams.get(‘item’);
となります。
ではNavParamsはどこから提供されているのか、
有る程度慣れてくれば簡単ですね。
NavParamsとNavControllerは
import { NavController, NavParams } from 'ionic-angular';

ionic-angularが提供してくれています。
これで受け取り側はパーペキですね。

では今度は送り側を見ていきます。
list.tsへ戻りましょう。
見るべき箇所はここです。

  itemTapped(event, item) {
this.navCtrl.push(ItemDetailsPage, {
item: item
});
}

list.htmlで (click)=”itemTapped($event, item)と書いているので
itemTappedの名前は何でもokです。
eventとitemを引数に持っているので
タップ、クリックした値(パラメーター)を持ってページを遷移します。
それを行っているのが
this.navCtrl.push(ItemDetailsPage, {
の部分です。
this.navCtrl.push
navCtrlはitem-datelisでも出てきました。
importも同じimport { NavController, NavParams } from ‘ionic-angular’;からで
constructor(public navCtrl: NavController, public navParams: NavParams) {
constructorで使用する名前を決めています。
これもsousinCtrlとかでも動きますよ。
navCtrlにpushをつけてやり、パラメーターの送信を定義します。
ちなみにpopというのもあります。
this.navCtrl.push(送るよ)(ItemDetailsPage(どこへ),{item:item(何を)}
最初のitemは受け渡し名なので分かりにくければitemd:itemなどにして、item-datelis.tsの方で
navParams.get(‘itemd’);等にしましょう。

ただ、これだとitemのtitleもnote、iconすべてを持っていくみたいです。
今調べているんですが、一部だけ持っていきたい場合どうすれば良いんだろう?
titleだけ持っていきたいとか。

今回でページ作成から簡単なテキスト挿入程度まで作成できる情報がそろったと思います。
次回辺りからは何かしら作ってみたいですね。