angularのhttpでレスポンスヘッダーを取得する

今回やりたかったことは以下。
angularの$http.getまたは$http.postでAPIへリクエストしたレスポンスヘッダーを取得するということ。
chromeの開発ツールからはレスポンスヘッダーを確認できたのだが、angularでは取り扱う場合にうまく取得できずに少しはまりました。

$http.get("path/to")
  .success(function(result, status, headers) {
    // headers()
  });

上記の形で取得できるはずなのだが、なぜか上手くいかなかった。
理由ははサーバー側で対応する必要があったみたい。

下記の形でレスポンスヘッダーを追加してやればすんなり取得できました。

Access-Control-Expose-Headers: <header-name>, <header-name>, ...

以上です

【ionic】collection-repeatで行の高さを動的にする

まだ調査中。無限スクロール実装するときにng-repeatよりcollection-repeatを使った方がパフォーマンスが良いらしい。とのことで。試していたら行の高さが1行目の高さに合わせられてしまうようで、高さを動的にする場合は高さを計算してやる必要がありそう。

テンプレート

<ion-content>
  <ion-list>
    <ion-item class="item-text-wrap item-remove-animate item-avatar item-icon-right"
              ng-repeat="item in items"
              item-height="getHeight(item)">
      <img ng-src="{{item.face}}">
      <h2>{{item.name}}</h2>
      <p>{{item.lastText}}</p>
    </ion-item>

    ・・・

  </ion-list>                                                                                                                                                                                                      

  <!-- 計算用に準備 -->
  <ion-item class="item-text-wrap item-remove-animate item-avatar item-icon-right"
            id="calculateItem">
    <img ng-src="">
    <h2></h2>
    <p></p>
  </ion-item>
</ion-content>

コントローラ

// 計算用DOM
var calculateItem = document.getElementById("calculateItem");

// 計算用DOMに値を入れて高さを計算して返す
$scope.getHeight = function(item) {
  var h2 = dummy.getElementsByTagName('h2')[0];
  var p = dummy.getElementsByTagName('p')[0];
  h2.textContent = item.name;
  p.textContent = item.lastText;
  return dummy.clientHeight;
};

とりあえずこれで動いた。collection-repeatの方がパフォーマンスが良いとかこのやりかたでパフォーマンスがよいかとかまではまだ調べられていない。以上です。

【Angularjs】PromiseでforEachで同期処理で順次実行する

こちらのコードを実行すると、testが1秒間隔で3回順次実行される。

var test = function() {
  var deffered = $q.defer();
  $timeout(function() {
    deffered.resolve();
  }, 1000);
  return deffered.promise;
};

var deffered = $q.defer();
var promise = deffered.promise;

promise
  .then(function() {
    var deffered = $q.defer();
    var promise = deffered.promise;
    for	(var i = 0; i < 3; i++) {
    // [1, 2, 3].forEach(function(v) { // forEachも一緒
      promise = promise.then(function() {
        return test();
      })
        .then(function() {
          var deffered = $q.defer();
          deffered.resolve();
          return deffered.promise;
	});
    });
    deffered.resolve();
    return promise;
  });
  deffered.resolve();

やりたかったのはこれだけ。以上です。

ionic(cordova)にて$ionicPopupをカスタマイズしてモーダルを作る

今回やりたかったのはこんな感じの画面。
初めはionicModalのサイズを変えてやろうとしていたのだが、モーダルのサイズを中のテキストとかにあわせてリサイズするのを自前で実装するのが手間でした。
で、少し調べたらionicPopupをカスタマイズしたら簡単にできたのでその手順をメモ。

f:id:yoppy0066:20170810130806g:plain:w250

ionic-close-popup をインストール

ポップアップの外をタップしたらポップアップを閉じるのを簡単に実現できるライブラリ。
https://github.com/mvidailhet/ionic-close-popup

インストール

$ bower install ionic-close-popup

index.htmlで読み込む

<script src="lib/ionic-close-popup/ionic-close-popup.js"></script>
ポップアップ画面を用意

ていっても今回はこれだけ

templates/custome_popup.html

Custom Popup!!
ポップアップを呼び出す

コントローラー

・・・
  .controller('DashCtrl', function(
    $scope,
    $ionicPopup,
    IonicClosePopupService
  ) {

    var popup = null;

    $scope.showPopup = function() {
      popup = $ionicPopup.alert({
        scope: $scope,
	cssClass: "custom-popup", // ★ 見た目をカスタマイズするためにCSSのクラスを追加
        templateUrl: "templates/custom_popup.html"
      });
      IonicClosePopupService.register(popup);
    };
  })
・・・

テンプレート

<ion-view view-title="Dashboard">
  <ion-content class="padding">
    <a ng-click="showPopup()">ポップアップOPEN</a>
  </ion-content>
  <style>                                                                                                                                                                                                          
  <!-- ポップアップサイズを指定することも可能 -->                                                                                                                                                                  
   .custom-popup .popup {
       width: 86%;
       height: 90%;
   }
   <!-- デフォルトで用意されているボタンとヘッダー部分を非表示に -->
   .custom-popup .popup-head,                                                                                                                                                                                      
   .custom-popup .popup-buttons {
       display:none;
   }
  </style>
</ion-view>

これだけでいけた。以上です

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>

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