ionic(cordova)にてアプリをリロードする

今回やりたかったことは、アプリでログアウトしたときなどにアプリをはじめから実行しなおしたい。ということ。いくつか試してみてうまくいくパターンとうまくいかなかったパターンをメモしておく。

・うまくいかなかったパターン

$state.go('path/to');
$window.location.reload();

・うまくいったパターン

window.location = "index.html";

うまくいかないパターンでもPCのブラウザだとうまくいくのだが、iPhone実機で確認すると真っ白になってうまくいかなかった。。
以上です

ionic(cordova)にて無限スクロールが途中で止まった時の対応

なんのこっちゃというタイトルですが。無限スクロール実装して、実機で検証していると意図せず途中で止まってしまうことがあった。不定期なので気づきずらかった。ちなみに無限スクロールに実装サンプルはこちらに書いて見た。で、以下のコードを無限スクロールを更新したいタイミングでいれておけば解消した。

$timeout(function() {
  $scope.$broadcast('scroll.infiniteScrollComplete');
});

以上です。

ionic(cordova)にて無限スクロールを実装する

今回やりたいこととしては以下
・サーバーからデータを取得してレスポンスがなくなるまで無限スクロール
・エラーがあったら再読み込みボタンを表示

普通の無限スクロールです。ひな形としてメモしておく。

f:id:yoppy0066:20170808180319g:plain:w250

想定するJSON

[{id: 1, name: "Tom"}, {id: 2, name: "Ben"},・・・]

コントローラー

  .controller('ChatsCtrl', function($scope, $http, $timeout) {
    $scope.items = [];

    // API URL                                                                                                                                                                                                     
    var url = "/path/to/api.json";

    // 1:リクエスト中 2:リクエスト完了 3:末尾に達した 9:エラー                                                                                                                                                     
    var status;

    $scope.get = function() {
      status = 1;
      $http.get(url)
        .success(function(result) {
          console.log(result);
          if (0 < result.length) {
            $scope.items = $scope.items.concat(result);
            $timeout(function() {
              $scope.$broadcast('scroll.infiniteScrollComplete');
            });
          } else {
            status = 3;
          }
        })
        .error(function(err) {
          console.log(err);
          status = 9;
        });
    };
    $scope.canWeLoadMoreContent = function() {
      return status != 3 && status != 9;
    };

    $scope.isError = function() {
      return status == 9;
    };

    $scope.retry = function() {
      status = 1;
      $timeout(function() {
        $scope.$broadcast('scroll.infiniteScrollComplete');
      });
    };

  })

テンプレート

<ion-list>
  <ion-item collection-repeat="item in items">                                                                                                                                                                     
    ・・・
  </ion-item>
</ion-list>
<ion-item ng-if="isError()" class="text-center">
  <button class="button button-clear button-assertive" ng-click="retry()">
    [エラー]タップで再読み込み
  </button>
</ion-item>
<ion-infinite-scroll
    ng-if="canWeLoadMoreContent()"
    on-infinite="get()"
    distance="5%">
</ion-infinite-scroll>

またコードずらずら書いただけだけど。以上です。

ionic(cordova)にてAndroidでもタブバー(ion-tabs)を画面下にする方法

Androidでion-tabsをデフォルトのまま使うとこんな感じで、画面上に設置され選択中のタブの下にラインが表示される。Android的にはこのUIが推奨されるのでしょうが、実案件ではiOSと合わせるということも多いはず・・・

f:id:yoppy0066:20170808154352p:plain:w250

angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])
.run(function($ionicPlatform) {
  ・・・
})
.config(function(
  $stateProvider,
  $urlRouterProvider,
  $ionicConfigProvider                                                                                                                                                                                             
) {

  ・・・ 

  // ★ここを追加
  $ionicConfigProvider.tabs.style("standard"); // 選択中のタブの下ラインを消す                                                                                                                                     
  $ionicConfigProvider.tabs.position("bottom"); // タブを画面下に                                                                                                                                                  
}

以上です。

ionic(cordova)の開発環境構築で最低限必要そうなプロジェクト開始手順をまとめておく

はじめに

いまさらバージョン1系かよ。
という内容だが個人的にはまだまだ使う機会ありそうなのでプロジェクトを作成してから開発に入るまでの最低限必要そうな手順をメモしておく。バージョン2は勉強中。

ツールバージョン

バージョンによって動いたり動かなかったりあるのでチーム開発するときは各バージョン揃えた方が良さそう。自分はこのバージョンで安定して開発できてる。

$ node -v
v6.10.3

$ npm -v
5.0.1

$ cordova -v
6.5.0

$ ionic -v
2.2.3
プロジェクトを作成

アプリ名やバンドルIDとかは決められるのであれば最初に指定してプロジェクト作成してしまうのが良さそう。きっと後で変更もできるのだろうけど、iOSAndroidどちらもあとからプロジェクト名とか変えるの手間だった記憶があるので決められるのであれば決めておいた方が楽そう。

$ ionic start SampleApp blank -a "SampleApp" -i com.sample.app
Androidをプロジェクトに追加

デフォルトではiOSのみなので必要であればAndroidも追加する。

$ ionic platform add android
.gitignore の編集

デフォルトの設定だとplugins以下もバージョン管理対象外となっている。package.jsonから各自がionic state resetなどを実行すればインストールできるからだ。けど、プラグインや各PCの環境の微妙な違い?とかでインストールできる人やできない人が出ることがある。根本的に解決できたらベストだけど、自分はplugins以下ごとバージョン管理する方針としてしまう。

.gitignore

node_modules/
platforms/
#plugins/   # ★ ここをコメント化
www/dist/*  # ★ ここを追加
必要なディレクトリ作成

ionic startで作られる基本的なディレクトリに追加。
www/dist ビルドしたJSファイルをここに
www/templates HTMLはここに
www/js/controllers コントローラはここに
www/js/services サービスはここに
www/js/values 定数定義はここに

$ mkdir -p www/dist www/templates www/js/controllers www/js/services www/js/values

僕はangular 自体をちゃんと理解できていないのでもっといい構成はあると思うけどいちおうメモしておく。

最低限必要なnpmモジュールを追加してgulpfileを設定

自分が最低限やりたいことは以下。
・とりあえずbower使いたい。
・分割して開発するJSファイルの結合を自動化したい。
・開発、ステージング、本番用の設定を切り替えたい。

モジュールの追加

$ npm install --save bower gulp-concat node-env-file

環境設定ファイルを作成
.env

#MODE=PRODUCTION
MODE=DEVELOPMENT

このファイルのMODEによって、結合の対象を動的に切り替えるようにする。
たとえばAPIを使うような場合にサーバーのURLを環境によって切り替えたい場合などに使う。

実際の記述はgulefile.jsに書く。
xxx.dev.js 開発アプリ(DEVELOPMENTの場合)
xxx.pro.js 本番アプリ(PRODUCTIONの場合)

gulpfile.jsの編集

var gulp = require('gulp');
var sass = require('gulp-sass');
var cleanCss = require('gulp-clean-css');
var rename = require('gulp-rename');

// ★モジュール追加
var concat = require('gulp-concat');
var env = require('node-env-file');

var paths = {
  sass: ['./scss/**/*.scss'],
  js: ['www/js/**/*.js', 'www/templates/**/*.html'] // ★ファイル変更の監視対象
};

// ★環境ごとに除外ファイルを切り替える
env(__dirname + "/.env");
var ex;
if (process.env.MODE == "PRODUCTION") {
  ex = ["!www/js/**/*.dev.js"];
} else {
  ex = ["!www/js/**/*.pro.js"];
}

gulp.task('default', ['sass']);

gulp.task('sass', function(done) {
  gulp.src('./scss/ionic.app.scss')
    .pipe(sass())
    .on('error', sass.logError)
    .pipe(gulp.dest('./www/css/'))
    .pipe(cleanCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({ extname: '.min.css' }))
    .pipe(gulp.dest('./www/css/'))
    .on('end', done);
});

// ★以下、ionic serve中の変更ファイルの監視とビルド時に分割したJSファイルを結合するタスク
gulp.task('serve:before', ['watch']);
gulp.task('build:before', ['js.concat-controllers', 'js.concat-services', 'js.concat-values']);

gulp.task("js.concat-controllers", function() {
  return gulp.src(["www/js/controllers/**/*.js"].concat(ex))
         .pipe(concat("controllers.js"))
         .pipe(gulp.dest("www/dist/js"));
});

gulp.task("js.concat-services", function() {
  return gulp.src(["www/js/services/**/*.js"].concat(ex))
        .pipe(concat("services.js"))
        .pipe(gulp.dest("www/dist/js"));
});

gulp.task("js.concat-values", function() {
  return gulp.src(["www/js/values/**/*.js"].concat(ex))
        .pipe(concat("values.js"))
        .pipe(gulp.dest("www/dist/js"));
});

gulp.task('watch', ['sass', 'js.concat-controllers', 'js.concat-services', 'js.concat-values'], function() {
  gulp.watch(paths.sass, ['sass']);
  gulp.watch(paths.js, ['js.concat-controllers', 'js.concat-services', 'js.concat-values']);
});

この状態で以下のタイミングでファイルの結合処理が実行される
・ionic serve中にファイルの変更があった場合
・ionic build、prepareなどを行う場合

ここまでで準備は完了なので以降で実際に開発してみる。

www/js/app.jsを編集
angular.module('starter', [
  'ionic',
  // ★これから開発する controller、service、valueを使えるように
  'starter.controllers',
  'starter.services',
  'starter.values'
])

.run(function($ionicPlatform) {
  // ・・・
})
// ★ルーティングの設定を追加
.config(function(
    $stateProvider,
    $urlRouterProvider
  ) {
  $stateProvider
  .state("index", {
    url: "/index",
    templateUrl: "templates/index.html",
    controller: "IndexCtrl"
  });

  $urlRouterProvider.otherwise("/index");
});

// ★これから開発する controller、service、valueを使えるように
angular.module('starter.values', []);
angular.module('starter.controllers', []);
angular.module('starter.services', []);
controllerとテンプレート(HTML)を追加する

www/js/controllers/index.js

angular.module('starter.controllers')
  .controller("IndexCtrl", function($scope) {
    $scope.test = "hello ionic.";
  });

www/templates/index.html

<ion-view>
  <ion-content>
    {{test}}
  </ion-content>
</ion-view>
ブラウザで確認する

ここまでファイルができた状態で「ionic serve」を実行するとgulpfile.jsで設定したとおりにdist/js以下にcontrollers.jsにファイルが追加されるはず。また、www/js以下とwww/templates以下のファイルを更新すると自動でここにファイルが出力されていく。最後に1番元となるindex.htmlに以下のように生成されたファイルを読み込むようにすれば、画面に「hello ionic.」と表示されるはず 

www/index.html

・・・
  <script src="js/app.js"></script>
  <script src="dist/js/controllers.js"></script>
</head>
<body ng-app="starter">
  <ion-nav-view>
    <!-- ここにControllerとテンプレートで出力する内容が表示される -->
  </ion-nav-view>
</body>

さいごにserviceとvalueのひな形もメモしておく。

www/js/services/sample.js

angular.module('starter.services')
  .service('SampleService', function() {
    this.my_func = function() {
      // なにか
    };
  });

www/js/values/config.dev.js

angular.module('starter.values')
  .value('config', {
    env_name: "開発環境"
  });

www/js/values/config.pro.js

angular.module('starter.values')
  .value('config', {
    env_name: "本番環境"
  });

まとまりないので、完全に自分用のメモになってしまったけど、以上です。

Amazon LinuxにNginxをバージョン指定してインストールする

公式サイト(http://nginx.org/en/linux_packages.html#stable)に、repoファイルの書き方がのってる。

ひな形

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/OS/OSRELEASE/$basearch/
gpgcheck=0
enabled=1

OS = centos、OSRELEASE=6とする。

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1

インストール可能なバージョンを調べる

# yum --showduplicates --disablerepo=amzn-main list nginx
Loaded plugins: priorities, update-motd, upgrade-helper
Installed Packages
nginx.x86_64       1.12.0-1.el6.ngx @nginx
Available Packages
nginx.x86_64       1.8.0-1.el6.ngx    nginx
nginx.x86_64       1.10.0-1.el6.ngx   nginx
nginx.x86_64       1.10.1-1.el6.ngx   nginx
nginx.x86_64       1.10.2-1.el6.ngx   nginx
nginx.x86_64       1.10.3-1.el6.ngx   nginx
nginx.x86_64       1.12.0-1.el6.ngx   nginx

バージョンを指定してインストールする
※ 今回は1.12をインストー

# yum -y install --disablerepo=amzn-main nginx-1.12.0

以上です

【angularjs】serviceで [$injector:unpr] Unknown provider が出た時の対応

半日くらいハマりました。

エラーが出てたコード

angular.module('myApp', []);

angular.module('myApp')
  .service('myService', function() {
    ・・・
  });

angular.module('myApp', ['ngCordova'])
  .service('myService2', function() {
    ・・・
  });

修正後のコード

angular.module('myApp', ['ngCordova']);

angular.module('myApp')
  .service('myService', function() {
    ・・・
  });

angular.module('myApp')
  .service('myService2', function() {
    ・・・
  });

以上です。