我知道有几种方法可以在角度js中加载指标(例如:https://gist.github.com/maikeldaloo/5140733)。
但是他们要么必须为每一次调用配置,要么 - 如果他们按照我的意愿全局行动 - 只需应用于http请求,但不应用于服务中使用的$ q-promises。
到目前为止,我见过的全球负载指标与
一起使用$httpProvider.responseInterceptors.push(interceptor);
$q
有类似$qProvider.reponseInterceptors
的内容吗?如果没有,那么实现这种功能最方便的方法是什么?例如,是否可以使用某种类型的装饰器图案?
答案 0 :(得分:16)
虽然我发现它非常复杂,不必要且可能已损坏,但可以装饰$q
并覆盖其defer
功能。
每次有人要求新的defer()
时,它会运行您自己的版本,这也会增加一个计数器。在分发defer
对象之前,您注册finally
回调(仅Angular 1.2.0,但always
也可能适合)以减少计数器。
最后,您向$rootScope
添加一个监视,以监控此计数器何时大于0(比pendingPromisses
中的$rootScope
更快并且像ng-show="pendingPromisses > 0"
那样绑定)。< / p>
app.config(function($provide) {
$provide.decorator('$q', ['$delegate', '$rootScope', function($delegate, $rootScope) {
var pendingPromisses = 0;
$rootScope.$watch(
function() { return pendingPromisses > 0; },
function(loading) { $rootScope.loading = loading; }
);
var $q = $delegate;
var origDefer = $q.defer;
$q.defer = function() {
var defer = origDefer();
pendingPromisses++;
defer.promise.finally(function() {
pendingPromisses--;
});
return defer;
};
return $q;
}]);
});
然后,绑定到继承自$rootScope
的范围的视图可以具有:
<span ng-show="loading">Loading, please wait</span>
(这在具有隔离范围的指令中不起作用)
直播here。
答案 1 :(得分:8)
在为当前稳定1.2.0工作的官方文档中有一个很好的例子。
http://docs.angularjs.org/api/ng.$http(页面的前四分之一,搜索拦截器)
我对这些文档的提取引出了我的解决方案:
angular.module('RequestInterceptor', [])
.config(function ($httpProvider) {
$httpProvider.interceptors.push('requestInterceptor');
})
.factory('requestInterceptor', function ($q, $rootScope) {
$rootScope.pendingRequests = 0;
return {
'request': function (config) {
$rootScope.pendingRequests++;
return config || $q.when(config);
},
'requestError': function(rejection) {
$rootScope.pendingRequests--;
return $q.reject(rejection);
},
'response': function(response) {
$rootScope.pendingRequests--;
return response || $q.when(response);
},
'responseError': function(rejection) {
$rootScope.pendingRequests--;
return $q.reject(rejection);
}
}
});
然后,您可以在ng-show表达式中使用pendingRequests&gt; 0。
答案 2 :(得分:5)
自OP提出要求以来,这是基于我们正在使用的应用程序的方法。此方法 NOT 更改$q
的行为,而是添加非常简单的 API来处理需要某种可视指示的promise。虽然这需要在每个使用的地方进行修改,但它只是一个单行。
有一项服务,比如ajaxIndicator
,知道如何更新部分UI。每当类似承诺的对象需要提供指示,直到承诺得到解决,我们使用:
// $http example:
var promise = $http.get(...);
ajaxIndicator.indicate(promise); // <--- this line needs to be added
如果您不想继续提及承诺:
// $http example without keeping the reference:
ajaxIndicator.indicate($http.get(...));
或者使用资源:
var rc = $resource(...);
...
$scope.obj = rc.get(...);
ajaxIndicator.indicate($scope.obj);
(注意:对于Angular 1.2,这需要tweeking,因为资源对象上没有$then()
。)
现在在根模板中,您必须将指标绑定到$rootScope.ajaxActive
,例如:
<div class="ajax-indicator" ng-show="ajaxActive"></div>
(从我们的源代码修改。)警告:此实现不考虑嵌套调用! (我们的要求是UI阻塞,因此我们不希望嵌套调用;如果感兴趣,我可以尝试增强此代码。)
app.service("ajaxIndicator", ["$rootScope"], function($rootScope) {
"use strict";
$rootScope.ajaxActive = false;
function indicate(promise) {
if( !$rootScope.ajaxActive ) {
$rootScope.ajaxActive = true;
$rootScope.$broadcast("ajax.active"); // OPTIONAL
if( typeof(promise) === "object" && promise !== null ) {
if( typeof(promise.always) === "function" ) promise.always(finished);
else if( typeof(promise.then) === "function" ) promise.then(finished,finished);
else if( typeof(promise.$then) === "function" ) promise.$then(finished,finished);
}
}
}
function finished() {
$rootScope.ajaxActive = false;
}
return {
indicate: indicate,
finished: finished
};
});
答案 3 :(得分:1)
几个星期前我遇到了同样的大问题,我碰巧做了一些指令来表示动作按钮和ng-repeat内容加载的加载状态。
我只是花了一些时间把它推到了github上: https://github.com/ocolot/angularjs_loading_buttons
我希望它有所帮助。