窓際BLOG

プログラミングの学習メモや書籍の感想等を公開していきます。

Ionic:スワイプでページ更新する方法のメモ

Ionicで下スワイプでページ更新を行う方法をメモφ(..)

↓実装イメージはこんな感じです。

f:id:madogiwa0124:20171112232529g:plain

手順

概要

Ionicでスワイプでページ更新を実装するには、ion-refresherを使用します。
Viewのion-content内にion-refresherを配置し、(ionRefresh)="doRefresh($event)"のように実行メソッドを定義します。

詳細は下記を参照頂ければ!※Ionicの公式ドキュメントです

Refresher - Ionic API Documentation - Ionic Framework

Viewへの配置

下記のようにView内のion-content配下にion-refresherを配置します。

<ion-content no-padding>
  <ion-refresher (ionRefresh)="doRefresh($event)">
    <ion-refresher-content></ion-refresher-content>
  </ion-refresher>
</ion-content>

更新処理の実行及び完了の実装

Viewへの配置が終わったら.ts側にページ更新及び完了の処理を実装していきます。
下記の実装では、API呼び出しによるデータ取得の完了または、3秒経過したら完了とし、ローディングを終了させています。

@IonicPage()
  
@Component({
  selector: 'page-page-index',
  templateUrl: 'page-index.html',
})
export class PageIndexPage {
  pages = [];
  result = '';
  api_url = 'https://moook.herokuapp.com/pages.json';
  refresher = null;

  constructor(public navCtrl: NavController, public navParams: NavParams, private http: Http, public loadingCtrl: LoadingController) {
    // ロード画面を表示
    this.presentLoading();
    // APIからデータを取得
    this.get_pages_data();
  }

  doRefresh(refresher) {
    this.refresher = refresher;
    // APIからデータを取得
    this.get_pages_data();
    // タイムアウトの設定
    setTimeout(() => {
      // ページ更新を完了とし、処理を中断
      refresher.complete();
    }, 3000);
  }

  get_pages_data(){
    this.http.get(this.api_url).subscribe(
      respons => {
        let result = respons.text();
        this.pages = [];
        JSON.parse(result || null).forEach(data => {
          this.pages.push(new Page(data)); 
        });
        if (this.refresher != null) {
          // データ取得が終わったら完了
          this.refresher.complete();
        }
      },
      error => {
        let result = 'faild : '+ error.statusText;
        console.log(result);
      }
    );
  }

}

完全なソースコードは下記に配置してありますφ(..)

github.com

以上です。

Ionic:読み込み中にローディングのポップアップを表示する

Ionicでローディングのポップアップを表示する手順をメモφ(..)

↓イメージはこんな感じです。
f:id:madogiwa0124:20171112215240g:plain

手順

Ionicでローディング画面を表示するにはLoadingControllerを使用します。
LoadingControllerの使い方の概要は下記の通りです。

methods memo
create ローディング画面を作成
present ローディング画面を表示
dismiss ローディング画面を非表示化

詳細は、下記を参照頂ければ!※Ionicの公式ドキュメントです。

↓Loadingコンポーネントの説明とデモ ionicframework.com

↓LoadingControllerのAPIドキュメント ionicframework.com

今回は、現在開発中のMoook.FrontendでAPIからデータを取得中にローディング画面を表示してみました。
下記がソースコードです。※必要部分だけ抜粋しています。

// ローディング用のモジュールをインポート
import { LoadingController } from 'ionic-angular';

@IonicPage()
  
@Component({
  selector: 'page-page-index',
  templateUrl: 'page-index.html',
})

export class PageIndexPage {
  pages = [];
  result = '';
  api_url = 'https://moook.herokuapp.com/pages.json';
  loader = null;
  // コンストラクタでLoadingControllerの変数を宣言
  constructor(public navCtrl: NavController, public navParams: NavParams, private http: Http, public loadingCtrl: LoadingController) {
    // ロード画面を表示
    this.presentLoading();
    // APIからデータを取得
    this.get_pages_data();
  }

  presentLoading() {
    this.loader = this.loadingCtrl.create({
      content: "Please wait...",  // 表示する文字列
      duration: 3000  // タイムアウト値(自動で消えるまでの時間)
    });
    // ローディング画面を表示
    this.loader.present();
  }

  get_pages_data(){
    this.http.get(this.api_url).subscribe(
      respons => {
        let result = respons.text();
        this.pages = [];
        JSON.parse(result || null).forEach(data => {
          this.pages.push(new Page(data)); 
        });
        if (this.loader != null) {
          // ローディング画面を非表示
          this.loader.dismiss();
        }
      },
      error => {
        let result = 'faild : '+ error.statusText;
        console.log(result);
      }
    );
  }
}

ソースコードの全体が知りたい人はGithubからどうぞヽ(´エ`)ノ

github.com

Ionic:API呼び出し処理の実装方法メモ

Moookのモバイル対応でAPIからデータを取得する対応をしたので、その方法を備忘目的でメモφ(..)

↓こんな感じでMoook(https://moook.herokuapp.com/pages)から取得したデータをIonic側で取得し、表示しています。

f:id:madogiwa0124:20171105115923g:plain

やりかた

モジュールのインポート

まずは、app.module.tshttpモジュールを追記し、API呼び出しに使用するモジュールをインポートします。

/* 省略 */
import { HttpModule } from '@angular/http'; // 追記

@NgModule({
  declarations: [
    MyApp,
    HelloIonicPage,
    ItemDetailsPage,
    ListPage,
    PageIndexPage,
    PageShowPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
    HttpModule // 追記
  ],
/* 省略 */
})
export class AppModule {}

API呼び出し処理の実装

モジュールをインポートしたらコンポーネント側でAPI呼び出し処理を実装します。

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { PageShowPage } from '../page-show/page-show';
import { Http } from '@angular/http';  // 追記

/**
 * Generated class for the PageIndexPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@IonicPage()
  
@Component({
  selector: 'page-page-index',
  templateUrl: 'page-index.html',
})
export class PageIndexPage {
  pages = [];
  result = '';
  api_url = 'https://moook.herokuapp.com/pages.json';

  constructor(public navCtrl: NavController, public navParams: NavParams, private http: Http) {
    this.get_pages_data();
  }

  get_pages_data(){
   // API呼び出し処理
    this.http.get(this.api_url).subscribe(
     // 成功時
      respons => {
        let result = respons.text();
        this.pages = JSON.parse(result || null);
      },
      // 失敗時
      error => {
        let result = 'faild : '+ error.statusText;
        console.log(result);
      }
    );
  }
}

まとめ

とりあえずIonicでのAPI呼び出し処理の実装をまとめてみましたφ(..)
まだまだ、APIのURLを共通化したりとか、HTTP呼び出し処理の共通化とか、まだまだ考慮しないといけない点はあると思いますが、これから色々勉強していこうと思います・・・!
(誰か教えてください。。。)

RubyonRails:deviseのcurrent_userの返り値をカスタマイズする

deviseのヘルパーメソッドcurrent_userの返り値がデフォルトだとnilになるが、 空のUserインスタンスを返したかったけどハマったので、やり方をメモφ(..)

やり方

application_controller.rbcurrent_userをoverrideする。
しかし、alias_method :devise_current_user, :current_userで、aliasを記載する必要があるため注意。

class ApplicationController < ActionController::Base
  alias_method :devise_current_user, :current_user
  def current_user
    if devise_current_user.nil?
      User.new
    else
      User.find_by_id(devise_current_user.id)
    end
  end
end

しかし

一旦上記手順でやろうとしたが、このやり方だとuser_signed_in?等が上手く動かない等の問題が発生してしまいました。。。
※current_userがnilかどうかでログイン状態を判定しているため、未ログイン時に空のUserインスタンスが設定されていると不正にログインされているように判定されてしまっているように思えた。。。

そのため、controllercurrent_userインスタンス変数に格納し、それをnull判定して空のインスタンスを設定してViewでもそれを参照するようにした。
DBアクセスも減るし、ライブラリとの依存も減る気がするので、なかなか良いんじゃないかと思いました。

class PagesController < ApplicationController
  before_action :set_user

  def index
    # ログイン有無により処理を分岐
    if !@user.id.nil?
      @pages = Page.favorited_pages(current_user).page(params[:page])
      @favorites = Favorite.find_by(user_id: current_user.id)
    else
      @pages = Page.all.order('updated_at DESC').page(params[:page])
    end
  end

  private

    def set_user
      # current_userがnilだったら空のUserインスタンスを設定
      @user = current_user || User.new
    end
end

参考

codenote.net

JavaScript:Anglar勉強整理メモ - 各設定ファイルの役割と概要 -

最近、Angularの勉強を下記本で勉強しているので、頭の整理がてらメモを投稿してみる。

Angularアプリケーションプログラミング

Angularアプリケーションプログラミング

今回は、Angularで使われる設定ファイルの役割と概要についてです。

基本ライブラリの挙動を宣言する

設定ファイル

設定が必要となるファイル

設定ファイル 概要
pakage.json Angular及びnode.jsで使用するライブラリを管理
tsconfig.json TypeScriptのコンパイラの動作を定義
systemjs.config.js モジュールローダー(SystemJS)の設定情報
pakage.json

Node.jsの設定ファイル、現在のアプリ及び使用しているライブラリを管理する。
npm install実行時に当該ファイルに記載されているライブラリをインストールする。

# ライブラリを追加でインストールする
npm install module_name --save

# save:dependenciesパラメーターへに記録
# 参考:勉強メモ/npmの使い方(node.js=v0.11.16, npm=2.3.0, 2015-03時点)
# https://qiita.com/msakamoto_sf/items/a1ae46979a42d6948ebd
tsconfig.json

TypeScriptをコンパイルする際の挙動を管理する。

{
  "compilerOptions": {
    "target": "es5",                // 生成するJavaScriptのバージョン 
    "module": "commonjs",           // 生成するJavascriptのモジュール形式
    "moduleResolution": "node",     // モジュールの解決方法
    "sourceMap": true,              // ソースマップを生成するかどうか
    "emitDecoratorMetadata": true,  // デコレーターのためのメタデータを出力するかどうか
    "experimentalDecorators": true, // デコレーターを有効にするかどうか
    "lib": [ "es2015", "dom" ],     // コンパイル時にインクルードされるライブラリ
    "noImplicitAny": true,          // 暗黙的なAny型への変換を行うかどうか
    "suppressImplicitAnyIndexErrors": true // インデックスアクセス時のnolmplicitAnyエラーを抑制
  }
}
systemjs.config.js

SystemJSとは、JavaScriptのモジュールを動的にロードするためのライブラリ。
各ライブラリへのエイリアスやデフォルトでロードするファイル等を定義する。

(function (global) {
  System.config({
    paths: {
      // パスのエイリアス設定
      'npm:': 'node_modules/'
    },
    // モジュールの短縮名を定義
    map: {
      // our app is within the app folder
      'app': 'app',

      // Angler標準モジュール
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      /* 省略 */
    },
    // モジュールのロード方法s
    packages: {
      app: {
        defaultExtension: 'js',
        meta: {
          './*.js': {
            loader: 'systemjs-angular-loader.js'
          }
        }
      },
      rxjs: {
        defaultExtension: 'js'
      }
    }
  });
})(this);

以上

JavaScript:Anglar勉強整理メモ - サンプルアプリの実行と概要について -

最近、Angularの勉強を下記本で勉強しているので、頭の整理がてらメモを投稿してみる。

Angularアプリケーションプログラミング

Angularアプリケーションプログラミング

今回は、Angularの基本についてです。


Angularの基本

Angular利用するための準備

サンプルプログラムのクローン

rem サンプルプログラムのクローン
$ git clone https://github.com/angular/quickstart

Angularアプリの基本構造

# Quickstartプロジェクトのフォルダ構成
# ★:最低限必要なファイル
quickstart
├src・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・アプリ本体を格納するフォルダ
│├index.html・・・・・・・・・・・・・・・・・・・・・・トップページ★
│├main.ts・・・・・・・・・・・・・・・・・・・・・・・・・スタートアップファイル★
│├style.css・・・・・・・・・・・・・・・・・・・・・・・標準のスタイルシート
│├system.config.js・・・・・・・・・・・・・・・・System.jsの設定ファイル★
│├tsconfig.js・・・・・・・・・・・・・・・・・・・・・TypeScriptコンパイラの設定情報
│└app・・・・・・・・・・・・・・・・・・・・・・・・・・・・・Angularアプリ関連のコード一式
│  ├app.cmnponent.ts・・・・・・・・・・・・・・ルートコンポーネント★
│  ├app.component.spec.ts・・・・・・・・・コンポーネントのテストスクリプト
│  └app.module.ts・・・・・・・・・・・・・・・・・ルートモジュール★
├e2e・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・E2Eテスト関連のスクリプト
│├app.e2e.spec.ts・・・・・・・・・・・・・・・・・E2Eテストスクリプト
│└ts.config.json・・・・・・・・・・・・・・・・・・TypeScriptコンパイラの設定情報
├karma.conf.js・・・・・・・・・・・・・・・・・・・・・karma設定ファイル
├package.json・・・・・・・・・・・・・・・・・・・・・・パッケージ情報ファイル
├protractor.config.js・・・・・・・・・・・・・・Protractor設定ファイル
└tslint.json・・・・・・・・・・・・・・・・・・・・・・・tslint設定情報

Angularアプリの実行

rem ライブラリのインストール
$ npm install
rem サーバーを起動
$ npm start

実行画面
f:id:madogiwa0124:20171016001213p:plain

Angularの基本構文の確認

モジュール

モジュールとは?:ソースコードの集合体

種類 概要
ルートモジュール アプリ起動時に実行されるモジュール
サブモジュール アプリの特定機能単位に実行されるモジュール
Anglerモジュール Angularがフレームワークとして提供するモジュール

ルートモジュールapp.module.tsを例に概要を説明

// Angularモジュールのインポート
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

// アプリを構成するコンポーネントのインポート
import { AppComponent }  from './app.component';

/* モジュール構成の定義
   この定義によりAngular上でモジュールとして扱えるようになる。
   ・imports:現在のモジュールで使用する他のモジュール
   ・declarations:現在のモジュールに属するコンポーネントなど
   ・bootstrap:アプリで最初に起動すべきルートコンポーネント
*/
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})

// モジュールクラスの定義
// export:他モジュールから参照可能
export class AppModule { }

コンポーネント

コンポーネント:UI部品
ルートコンポーネント:最初に呼ばれるコンポーネント

ルートコンポーネントapp.component.tsを例に説明

// コンポーネントを定義するために必要なオブジェクトのインポート
import { Component } from '@angular/core';

/* コンポーネントの構成情報を定義
   この定義によりAngular上コンポーネントとして扱えるようになる。
   ・selector:コンポーネントを適用すべき要素
   ・template:コンポーネントに適用するView
   例)<my-app></my-app>に<h1>Hello Angular</h1>を反映する
*/
@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>`,
})

// コンポーネントクラスの定義
// プロパティとしてnameを宣言し'Angular'を代入
export class AppComponent  { name = 'Angular'; }

テンプレートへ変数を埋め込む Interpolation(補完)

Interpolation(補完)構文{{...}}を用いることで、コンポーネントクラスのプロパティをテンプレートに代入することが可能。


メインページ

アプリが動作するメインページindex.html

<!DOCTYPE html>
<html>
  <head>
    <title>Angular QuickStart</title>
    <base href="/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- 必要なモジュールのインポート -->
    <script src="node_modules/core-js/client/shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    
    <!-- システム情報設定をインポート -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('main.js').catch(function(err){ console.error(err); });
    </script>

  </head>

  <body>
    <!-- ルートコンポーネントの表示領域 -->
    <my-app>Loading AppComponent content here ...</my-app>
  </body>
</html>

以上

HTML+CSS+JavaScriptでネイティブアプリが作れる - ionic入門 -

最近、ionicを使ってみているので日本語のドキュメント少ないし、頭の整理も兼ねて入門記事を書いてみるφ(..)

ionicとは

ionicとは、HTML+CSS+JavascriptといったWebの技術を使ってネイティブアプリが開発出来るオープンソースフレームワークです。

Know how to build websites? Then you already know how to build mobile apps. Ionic Framework offers the best web and native app components for building highly interactive native and progressive web apps. https://ionicframework.com/より引用
ウェブサイトを構築する方法を知っていますか?次に、モバイルアプリを構築する方法を既に知っています。 Ionic Frameworkは、高度にインタラクティブなネイティブおよびプログレッシブなWebアプリケーションを構築するための、最高のWebおよびネイティブアプリコンポーネントを提供します。(Google翻訳)

ionicframework.com

ionicにはネイティブアプリの部品やアクションを再現した各種コンポーネントやアイコンが揃っていて、それらをHTMLの要素として配置しCSSでデザインを整えたり、JavaScript(TypeScirpt + AngularJS)で処理を実装することでネイティブアプリを開発することが出来ます!・ω・

↓ちなみにこんな感じのが作れます。 f:id:madogiwa0124:20171001224730g:plain

サンプルアプリを動かしてみる

Ionicをお手軽に試せるようにionicの公式ホームページにチュートリアルが記載されているので、それを元に環境構築をして、サンプルアプリを動かしてみようと思います!

ionicframework.com

ionicを動かす環境をつくる

node.jsのインストール

まずは、下記サイトでインストーラーを取得し、node.jsをインストールします。

Node.js

node.jsのバージョン管理等を行いたい人は、下記記事が参考になるかと思います。

qiita.com

ionicのインストール

node.jsがインストール出来たら、いよいよ下記コマンドを実行しionicをインストールします。

$ npm install -g cordova ionic

下記コマンド実行し、バージョン情報が返ってくれば完了です。

$ ionic -v
3.10.1

サンプルアプリを動かしてみる

サンプルアプリの作成

任意のフォルダで下記コマンドを実行し、Ionicのチュートリアル用のアプリケーションを作成します。

$ ionic start MyIonicProject tutorial

MyIonicProjectにアプリケーション名を指定しています。
また上記コマンドのtutorialの部分を変更するとことで色々なベースを元に作成することが出来ます。

tabs : a simple 3 tab layout
sidemenu: a layout with a swipable menu on the side
blank: a bare starter with a single page
super: starter project with over 14 ready to use page designs
tutorial: a guided starter project

サンプルアプリの実行

作成したアプリを実行するには作成したプロジェクトファイルに移動し、ionic serveを実行します。

rem プロジェクトフォルダに移動
$ cd MyIonicProject/
rem ionicのアプリケーションを実行
$ ionic serve

下記のような画面が表示されたら成功です!

f:id:madogiwa0124:20171001234056p:plain

※ionicで作成したアプリケーションの表示を確認する場合は、デベロッパーツールを表示し、toggle devise toolbarを使用すると便利です。

developers.google.com

サンプルアプリにページを追加してみる

サンプルページが上手く動いたところで、新規にページを追加しionicの実装イメージを掴みます。

ページの生成

ionicにページを追加する場合は、下記コマンドを実行します。

rem ionic generate [<type>] [<name>]
$ ionic generate page PageIndex 
[OK] Generated a page named PageIndex!

app/src/pages配下にフォルダが作成されていればOKです。

作成ページの構成概要

先程のコマンドを実行すると下記のようなフォルダ・ファイルが生成されます。

page-index
 ├page-index.html
 ├page-index.module.ts
 ├page-index.scss
 └page-index.ts

この中でも主に編集するのは、page-index.htmlpage-index.scsspage-index.tsの3つです。

ファイル 説明
page-index.html コーポネントの配置及びjs側で保持している値の紐付けを行います。
page-index.scss アプリのデザインに関わる部分をSCSS(≒CSS)で記載します。
page-index.ts クリック時や画面表示後等で実行される処理をTypeScript+AngularJSで記載します。

ページ遷移処理の実装

それでは、新規ページへ遷移する処理を記載していきます。

ページの登録

まずは、追加したページをアプリに登録します。

app.module.ts

/* 省略 */
import { PageIndexPage } from '../pages/page-index/page-index';

@NgModule({
  declarations: [
    MyApp,
    HelloIonicPage,
    ItemDetailsPage,
    ListPage,
    PageIndexPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp),
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HelloIonicPage,
    ItemDetailsPage,
    ListPage,
    PageIndexPage,
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
/* 省略 */

追加したページをルートに設定してみる

ルートページの設定は、app.components.jsで行うことが出来ます。
ルートページに設定したページがアプリ起動時に表示されるようになります。

app.components.js

/* 省略 */
import { PageIndexPage } from '../pages/page-index/page-index';
/* 省略 */
export class MyApp {
  // 新規追加ページを代入
  rootPage = PageIndexPage;
 /* 省略 */
 openPage(){
   this.menu.close();
   // ルートページに遷移
   this.nav.setRoot(page.component);
 }
}

遷移したページに値を受け渡してみる

一覧画面から詳細画面に遷移するような処理を行うためには、下記のような手順が必要です。

  1. html側でクリックイベントを発火
  2. クリックされた要素の情報を引数にページ遷移のメソッドを呼び出す
  3. 引数をパラメーターに設定し、ページ遷移を行う
  4. 遷移先でパラメーターを受領する

具体的な実装

page-index.html

<button ion-button color="primary" (click)="gotoPageShowPage(page)">

page-index.ts

  // 遷移先ページをインポート
  import { PageShowPage } from '../page-show/page-show';
  /* 省略 */
  gotoPageShowPage(page) {
    // 引数をパラメーターに設定し、ページ遷移を行う。
    this.navCtrl.push(PageShowPage, {
      page: page
    }); 
  

page-show.ts

  constructor(public navCtrl: NavController, public navParams: NavParams) {
    // パラメーターを取得
    this.page = navParams.get('page');
  }

おわりに

ionicを使えばHTML+CSS+JSといったWebの技術を使ってiosAndroidのアプリをつくることが出来ます。
私もまだまだ勉強中ですが、これからもなにかあれば投稿してみようと思います!φ(..)「