github に repo 作った。
通信開始時にぐるぐるを出して通信終了時にぐるぐるを消したい。こんなときは $httpProvider.interceptors
を使う。
こういったものを用意しておく。
'use strict';
(function () {
var $ = angular.element;
var styleTemplate = 'style="width: ${width}px; height: ${height}px; top: ${top}px;"';
var spinnerTemplate = '<div class="spinner-base" ${style}></div>';
var backdropTemplate = '<div class="spinner-backdrop" ${style}></div>';
var numofConnections = 0;
var removeTargets = [];
var show = function () {
var style = styleTemplate
.replace('${top}', window.pageYOffset || 0)
.replace('${height}', window.innerHeight || 0)
.replace('${width}', window.innerWidth || 0);
var spinner = $(spinnerTemplate.replace('${style}', style));
var backdrop = $(backdropTemplate.replace('${style}', style));
var body = $(document.querySelector('body'));
spinner.append((new Spinner()).spin().el);
body.append(backdrop);
body.append(spinner);
removeTargets.push(spinner);
removeTargets.push(backdrop);
};
var hide = function () {
angular.forEach(removeTargets, function (target) {
target.remove();
});
removeTargets = [];
};
var module = angular.module('interceptors', []);
module.factory('spinnerInterceptor', ['$q', function ($q) {
return {
request: function (config) {
if (numofConnections++ === 0) {
show();
}
return config;
},
response: function (response) {
if (--numofConnections === 0) {
hide();
}
return response;
},
responseError: function (rejection) {
if (--numofConnections === 0) {
hide();
}
return $q.reject(rejection);
}
};
}]);
})();
/*
* spinner.css
* */
.spinner-backdrop {
z-index: 2000;
position: absolute;
background-color: black;
opacity: .1;
}
.spinner-base {
z-index: 2010;
position: absolute;
}
spin.js を使ってる。
で、見ての通りただの factory 。ただし、以下の 2 つの点がポイント。
- request, response, responseError というプロパティをもっている
- request と response は引数に渡された変数を返す関数になっている
- responseError は引数に渡された変数で reject する関数になっている
request は通信を投げる前に呼ばれる関数、 response は通信が返ってきたあとに呼ばれる関数、 Error が末尾についてるのはエラーが発生した場合のハンドラー。もちろん requestError もある。
2, 3 番目の条件はそういう決まりで、他にも似たような interceptor があって、登録された順に実行されると考えればいい。返り値が他の interceptor に渡されるので返さなかったり他の変なもの返したりするとまともに通信できなくなる。 responseError で reject せずにそのまま return したりするとエラーが解決されたものと解釈されて success コールバックが呼ばれたりする。
あとはまぁ jqLite なのでちょっと変な書き方になってるとかだけど細かいから気にしない。
実際の使い方はこう。
'use strict';
(function () {
var app = angular.module('spinner-sample', ['interceptors']);
// register spinner-interceptor
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('spinnerInterceptor');
}]);
app.controller('http-controller', [
'$http',
function ($http) {
var controller = this;
// with spinner !!
$http.get('items.json').success(function (data) {
controller.data = data;
});
}
]);
})();
最初に app.config
を使って $httpProvider.interceptors
に登録さえすればあとは勝手にぐるぐるを出してくれる。