中安拓也のブログ

プログラミングについて書くブログ

【JavaScript】Ionicで架空のECアプリを作成する #2 - 商品リスト画面を作る

f:id:l08084:20180429155759p:plain
今回作成する画面

前回の記事はこちら

ハイブリットモバイルアプリフレームワークのIonicを使って、架空のアパレルショップにおける注文アプリを作成する。

第2回目である今回は、商品リスト(ホーム)画面を作成するところまで

  • デモ

こちらのURLで、完成版のアプリを実際に操作することができます

https://l08084.github.io/ionic-sample-shopping-app/www

  • GitHubリポジトリ

github.com

バージョン情報

Angular(JavaScriptのWebフレームワーク)ベースの、ハイブリットモバイルアプリ用フレームワークである「Ionic」を使っている

  • ionic-angular@3.9.2
  • Angular@5.2.10

JSONにアクセスするサービスクラスを作る

第1回目の記事で商品データ(JSON)を作成したので、それにHTTPアクセスするサービスクラスを作る。

サービスクラス作成

ターミナルを立ち上げて、下記のIonic CLIコマンドを実行

$ ionic generate provider product

Angular CLIのng generate serviceにあたる上記のコマンドで、src/providers/product/product.tsファイルが作成される

NgModuleの設定

HttpClientModule@NgModule.importsの配列に追加する

src/app/app.module.ts:

// ...省略

// add this!
import { HttpClientModule } from "@angular/common/http";

@NgModule({
  declarations: [MyApp, AboutPage, ContactPage, HomePage, TabsPage],
  // imports:[]にHttpClientModuleを追加
  imports: [BrowserModule, IonicModule.forRoot(MyApp), HttpClientModule],
  // ...省略
})
export class AppModule {}

サービスクラスの実装

作成したサービスクラスにローカルのJSONにHTTPアクセスするコードを書く

src/providers/product/product.ts:

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Product } from "../../model/product.model";

@Injectable()
export class ProductProvider {
  constructor(public http: HttpClient) {}

  retrieve(): Observable<Product[]> {
    // JSONにアクセスして、結果をProduct[]に変換
    return this.http.get<Product[]>("assets/data/products.json");
  }
}

商品リスト画面コンポーネントクラス作成

続いて、商品リスト画面のコンポーネントクラスであるhome.tsとそのテンプレートファイルであるhome.htmlの内容を更新する。

src/pages/home/home.ts:

import { Component, OnInit } from "@angular/core";
import { NavController } from "ionic-angular";
import { Product, PRODUCT_TYPE } from "../../model/product.model";
import { ProductProvider } from "../../providers/product/product";

@Component({
  selector: "page-home",
  templateUrl: "home.html"
})
export class HomePage {
  productList: Product[];
  topsList: Product[];
  jacketList: Product[];

  constructor(
    private navCtrl: NavController,
    private productProvider: ProductProvider
  ) {}

  ionViewDidLoad() {
    // 全商品リストを取得
    this.productProvider.retrieve().subscribe(products => {
      this.productList = products;
      // トップス のみのリストを取得
      this.topsList = products.filter(
        product => product.type === PRODUCT_TYPE.tops
      );
      // ジャケット/アウター のみのリストを取得
      this.jacketList = products.filter(
        product => product.type === PRODUCT_TYPE.jacket
      );
    });
  }
}

HomePageクラスでは、下記のことを行なっている。

  • ProductProviderクラスのretrieve()メソッドを呼び出して、商品リストを取得
  • 商品リストから、トップス(PRODUCT_TYPE.tops)の商品のみをフィルタリング
  • トップスの商品リストを、プロパティtopsListにバインド
  • 商品リストから、ジャケット/アウター(PRODUCT_TYPE.jacket)の商品のみをフィルタリング
  • ジャケット/アウターの商品リストを、プロパティjacketListにバインド

src/pages/home/home.html:

<ion-header>
  <ion-navbar>
    <ion-title>Apparel</ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <ion-list>
    <ion-list-header>
      トップス
    </ion-list-header>
    <button ion-item *ngFor="let tops of topsList">
      <ion-thumbnail item-start>
        <img src="{{tops.imagePath}}">
      </ion-thumbnail>
      <h2>{{tops.name}}</h2>
      <p>¥{{tops.price}}</p>
    </button>
    <ion-list-header>
      ジャケット/アウター
    </ion-list-header>
    <button ion-item *ngFor="let jacket of jacketList">
      <ion-thumbnail item-start>
        <img src="{{jacket.imagePath}}">
      </ion-thumbnail>
      <h2>{{jacket.name}}</h2>
      <p>¥{{jacket.price}}</p>
    </button>
  </ion-list>
</ion-content>

home.htmlテンプレートでは、下記のことを行なっている。

  • 分類がトップスの商品配列topsListngForディレクティブを使って、リスト形式に表示
  • 分類がジャケット/アウターの商品配列jacketListngForディレクティブを使って、リスト形式に表示

動作確認

上記のコードを書いた段階でいったん動作確認をしてみる。

f:id:l08084:20180429155759p:plain
商品リスト(ホーム)画面

ちゃんとそれっぽい画面が表示されたので、今回はここまで。


次回の記事