$http
AngularJSのサービスを使用してAjax リクエストを作成しています。
Ajax リクエストの実行中にスピナー GIF (または別の種類のビジー インジケーター) を表示するにはどうすればよいですか?
ajaxstartevent
AngularJS のドキュメントに のようなものはありません。
$http
AngularJSのサービスを使用してAjax リクエストを作成しています。
Ajax リクエストの実行中にスピナー GIF (または別の種類のビジー インジケーター) を表示するにはどうすればよいですか?
ajaxstartevent
AngularJS のドキュメントに のようなものはありません。
これは特定のユースケースに大きく依存しますが、簡単な方法は次のようなパターンに従います。
.controller('MainCtrl', function ( $scope, myService ) {
$scope.loading = true;
myService.get().then( function ( response ) {
$scope.items = response.data;
}, function ( response ) {
// TODO: handle the error somehow
}).finally(function() {
// called no matter success or failure
$scope.loading = false;
});
});
そして、テンプレートでそれに反応します:
<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>
directive
とを使用したバージョンを次に示しng-hide
ます。
これにより、Angular のサービスを介したすべての呼び出し中にローダーが表示されます。$http
テンプレートでは:
<div class="loader" data-loading></div>
指令:
angular.module('app')
.directive('loading', ['$http', function ($http) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.isLoading = function () {
return $http.pendingRequests.length > 0;
};
scope.$watch(scope.isLoading, function (value) {
if (value) {
element.removeClass('ng-hide');
} else {
element.addClass('ng-hide');
}
});
}
};
}]);
要素にクラスを使用するng-hide
ことで、jquery を回避できます。
カスタマイズ: を追加interceptor
ローディングインターセプターを作成すると、条件に基づいてローダーを表示/非表示にすることができます。
指令:
var loadingDirective = function ($rootScope) {
return function ($scope, element, attrs) {
$scope.$on("loader_show", function () {
return element.removeClass('ng-hide');
});
return $scope.$on("loader_hide", function () {
return element.addClass('ng-hide');
});
};
};
インターセプター:
spinner
例: 次の場合は表示しないresponse.background === true;
request
および/またはresponse
設定$rootScope.$broadcast("loader_show");
または$rootScope.$broadcast("loader_hide");
ngResource を使用している場合、オブジェクトの $resolved 属性はローダーに役立ちます。
次のようなリソースの場合:
var User = $resource('/user/:id', {id:'@id'});
var user = User.get({id: 1})
ローダーをリソース オブジェクトの $resolved 属性にリンクできます。
<div ng-hide="user.$resolved">Loading ...</div>
これは、私が推測するスピナーを追加する最も簡単な方法です:-
これらの美しいスピナーのいずれかの div タグで ng-show を使用できます http://tobiasahlin.com/spinkit/ {{これは私のページではありません}}
そして、この種のロジックを使用できます
//ajax start
$scope.finderloader=true;
$http({
method :"POST",
url : "your URL",
data: { //your data
}
}).then(function mySucces(response) {
$scope.finderloader=false;
$scope.search=false;
$scope.myData =response.data.records;
});
//ajax end
<div ng-show="finderloader" class=spinner></div>
//add this in your HTML at right place
これは、サードパーティのライブラリ、インターセプター、または jQuery を必要としないスピナーを表示する簡単な方法です。
コントローラーで、フラグを設定およびリセットします。
function starting() {
//ADD SPINNER
vm.starting = true;
$http.get(url)
.then(function onSuccess(response) {
vm.data = response.data;
}).catch(function onReject(errorResponse) {
console.log(errorResponse.status);
}).finally(function() {
//REMOVE SPINNER
vm.starting = false;
});
};
HTML では、次のフラグを使用します。
<div ng-show="vm.starting">
<img ng-src="spinnerURL" />
</div>
<div ng-hide="vm.starting">
<p>{{vm.data}}</p>
</div>
このvm.starting
フラグはtrue
、XHR の開始時に設定され、XHR の完了時にクリアされます。
これは私にとってはうまくいきます:
HTML:
<div id="loader" class="ng-hide" ng-show="req.$$state.pending">
<img class="ajax-loader"
width="200"
height="200"
src="/images/spinner.gif" />
</div>
角度:
$scope.req = $http.get("/admin/view/"+id).success(function(data) {
$scope.data = data;
});
$http から返された promise が保留中の間、ng-show はそれを「真実」であると評価します。約束が解決されると、これは自動的に更新されます...これはまさに私たちが望んでいることです。
このようなことも試すことができます:
ディレクティブを作成:
myApp.directive('loader', function () {
return {
restrict: 'A',
scope: {cond: '=loader'},
template: '<span ng-if="isLoading()" class="soft"><span class="fa fa-refresh fa-spin"></span></span>',
link: function (scope) {
scope.isLoading = function() {
var ret = scope.cond === true || (
scope.cond &&
scope.cond.$$state &&
angular.isDefined(scope.cond.$$state.status) &&
scope.cond.$$state.status === 0
);
return ret;
}
}
};
});
次に、このようなものを mainCtrl に追加します
// Return TRUE if some request is LOADING, else return FALSE
$scope.isLoading = function() {
return $http.pendingRequests.length > 0;
};
HTML は次のようになります。
<div class="buttons loader">
<span class="icon" loader="isLoading()"></span>
</div>
.factory('authHttpResponseInterceptor', ['$q', function ($q) {
return {
request: function(config) {
angular.element('#spinner').show();
return config;
},
response : function(response) {
angular.element('#spinner').fadeOut(3000);
return response || $q.when(response);
},
responseError: function(reason) {
angular.element('#spinner').fadeOut(3000);
return $q.reject(reason);
}
};
}]);
.config(['$routeProvider', '$locationProvider', '$translateProvider', '$httpProvider',
function ($routeProvider, $locationProvider, $translateProvider, $httpProvider) {
$httpProvider.interceptors.push('authHttpResponseInterceptor');
}
]);
in your Template
<div id="spinner"></div>
css
#spinner,
#spinner:after {
border-radius: 50%;
width: 10em;
height: 10em;
background-color: #A9A9A9;
z-index: 10000;
position: absolute;
left: 50%;
bottom: 100px;
}
@-webkit-keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes load8 {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
DRYの概念を知っている場合、すべての答えは複雑であるか、すべてのリクエストにいくつかの変数を設定する必要があるか、非常に間違った方法です。ここでの簡単なインターセプターの例では、ajax の開始時にマウスを待機状態に設定し、ajax の終了時にマウスを自動に設定します。
$httpProvider.interceptors.push(function($document) {
return {
'request': function(config) {
// here ajax start
// here we can for example add some class or show somethin
$document.find("body").css("cursor","wait");
return config;
},
'response': function(response) {
// here ajax ends
//here we should remove classes added on request start
$document.find("body").css("cursor","auto");
return response;
}
};
});
アプリケーション構成にコードを追加する必要がありますapp.config
。ロード状態でマウスを変更する方法を示しましたが、ローダーのコンテンツを表示/非表示にしたり、ローダーを表示しているいくつかの css クラスを追加、削除したりできます。
Interceptor はすべての ajax 呼び出しで実行されるため、すべての http 呼び出しで特別なブール変数( $scope.loading=true/false など)を作成する必要はありません。
次のコードでディレクティブを作成します。
$scope.$watch($http.pendingRequests, toggleLoader);
function toggleLoader(status){
if(status.length){
element.addClass('active');
} else {
element.removeClass('active');
}
}
次の方法では、すべてのリクエストを記録し、すべてのリクエストが完了すると非表示になります。
app.factory('httpRequestInterceptor', function(LoadingService, requestCount) {
return {
request: function(config) {
if (!config.headers.disableLoading) {
requestCount.increase();
LoadingService.show();
}
return config;
}
};
}).factory('httpResponseInterceptor', function(LoadingService, $timeout, error, $q, requestCount) {
function waitAndHide() {
$timeout(function() {
if (requestCount.get() === 0){
LoadingService.hide();
}
else{
waitAndHide();
}
}, 300);
}
return {
response: function(config) {
requestCount.descrease();
if (requestCount.get() === 0) {
waitAndHide();
}
return config;
},
responseError: function(config) {
requestCount.descrease();
if (requestCount.get() === 0) {
waitAndHide();
}
var deferred = $q.defer();
error.show(config.data, function() {
deferred.reject(config);
});
return deferred.promise;
}
};
}).factory('requestCount', function() {
var count = 0;
return {
increase: function() {
count++;
},
descrease: function() {
if (count === 0) return;
count--;
},
get: function() {
return count;
}
};
})
http リクエスト呼び出しごとにローダーを表示する場合は、angular インターセプターを使用して http リクエスト呼び出しを管理できます。
ここにサンプルコードがあります
<body data-ng-app="myApp">
<div class="loader">
<div id="loader"></div>
</div>
<script>
var app = angular.module("myApp", []);
app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) {
return {
request: function ($config) {
$('.loader').show();
return $config;
},
response: function ($config) {
$('.loader').hide();
return $config;
},
responseError: function (response) {
return response;
}
};
}]);
app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
function ($stateProvider, $urlRouterProvider, $httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
}]);
</script>
</body>
これが私の実装で、ng-show とリクエスト カウンターと同じくらい簡単です。
$http へのすべてのリクエストに新しいサービスを使用します。
myApp.service('RqstSrv', [ '$http', '$rootScope', function($http, $rootScope) {
var rqstService = {};
rqstService.call = function(conf) {
$rootScope.currentCalls = !isNaN($rootScope.currentCalls) ? $rootScope.currentCalls++ : 0;
$http(conf).then(function APICallSucceed(response) {
// Handle success
}, function APICallError(response) {
// Handle error
}).then(function() {
$rootScope.currentCalls--;
});
}
} ]);
そして、現在の呼び出しの数に基づいてローダー ベースを使用できます。
<img data-ng-show="currentCalls > 0" src="images/ajax-loader.gif"/>
これが私の解決策であり、他の人がここに投稿したよりもはるかに簡単だと感じています。それがどれほど「きれい」かはわかりませんが、すべての問題を解決しました
「読み込み」と呼ばれるCSSスタイルがあります
.loading { display: none; }
ローディング div の html は何でもかまいませんが、いくつかの FontAwesome アイコンとスピン メソッドを使用しました。
<div style="text-align:center" ng-class="{ 'loading': !loading }">
<br />
<h1><i class="fa fa-refresh fa-spin"></i> Loading data</h1>
</div>
非表示にしたい要素には、次のように記述します。
<something ng-class="{ 'loading': loading }" class="loading"></something>
関数では、これをロード時に設定しました。
(function (angular) {
function MainController($scope) {
$scope.loading = true
私はSignalRを使用しているので、hubProxy.client.allLocks関数で(ロックを通過したときに)突き出します
$scope.loading = false
$scope.$apply();
これは、ページの読み込み時に {{someField}} も非表示にします。これは、読み込み時にクラスを読み込み、AngularJS が後でそれを削除するためです。