AngularJS:如何看服务变量?
我有一个服务,说:
factory('aService', ['$rootScope', '$resource', function ($rootScope, $resource) {
var service = {
foo: []
};
return service;
}]);
我想用foo
来控制以HTML格式呈现的列表:
<div ng-controller="FooCtrl">
<div ng-repeat="item in foo">{{ item }}</div>
</div>
为了让控制器能够检测到aService.foo
更新的时间,我已经将这个模式拼凑在了一起,并在控制器的$scope
添加aService,然后使用$scope.$watch()
:
function FooCtrl($scope, aService) {
$scope.aService = aService;
$scope.foo = aService.foo;
$scope.$watch('aService.foo', function (newVal, oldVal, scope) {
if(newVal) {
scope.foo = newVal;
}
});
}
这感觉是长期的,我一直在使用服务变量的每个控制器中重复它。 有没有更好的方法来完成观看共享变量?
如果你想避免$watch
的暴政和开销,你总是可以使用好的旧观察者模式。
在服务中:
factory('aService', function() {
var observerCallbacks = [];
//register an observer
this.registerObserverCallback = function(callback){
observerCallbacks.push(callback);
};
//call this when you know 'foo' has been changed
var notifyObservers = function(){
angular.forEach(observerCallbacks, function(callback){
callback();
});
};
//example of when you may want to notify observers
this.foo = someNgResource.query().$then(function(){
notifyObservers();
});
});
在控制器中:
function FooCtrl($scope, aService){
var updateFoo = function(){
$scope.foo = aService.foo;
};
aService.registerObserverCallback(updateFoo);
//service now in control of updating foo
};
在这种情况下,多个/未知对象可能对更改感兴趣,请使用正在更改的项目中的$rootScope.$broadcast
。
与其创建自己的监听器注册表(必须在各种$破坏条件下清理),您应该能够从相关服务中进行$broadcast
。
您仍然必须在每个侦听器$on
编写$on
处理程序,但该模式与多次调用分离为$digest
,从而避免了长时间运行的监视器的风险。
通过这种方式,监听器也可以来自DOM和/或不同的子范围,而不会改变服务的行为。
**更新:示例**
广播可能会影响“全球”服务,这可能会影响您的应用中无数其他事物。 一个很好的例子是一个用户服务,其中有许多事件可以发生,例如登录,注销,更新,空闲等。我认为这是广播最有意义的地方,因为任何范围都可以监听事件,而无需甚至注入服务,并且它不需要评估任何表达式或缓存结果来检查更改。 它只是开火和忘记(所以要确保它是一个即发即忘通知,而不是需要采取行动的事情)
.factory('UserService', [ '$rootScope', function($rootScope) {
var service = <whatever you do for the object>
service.save = function(data) {
.. validate data and update model ..
// notify listeners and provide the data that changed [optional]
$rootScope.$broadcast('user:updated',data);
}
// alternatively, create a callback function and $broadcast from there if making an ajax call
return service;
}]);
当save()函数完成且数据有效时,上述服务将向每个范围广播一条消息。 或者,如果它是$资源或ajax提交,请将广播呼叫转移到回调中,以便在服务器响应时触发。 广播很适合这种模式,因为每个听众只是等待事件而不需要检查每个消息的范围。 听众会看起来像:
.controller('UserCtrl', [ 'UserService', '$scope', function(UserService, $scope) {
var user = UserService.getUser();
// if you don't want to expose the actual object in your scope you could expose just the values, or derive a value for your purposes
$scope.name = user.firstname + ' ' +user.lastname;
$scope.$on('user:updated', function(event,data) {
// you could inspect the data to see if what you care about changed, or just update your own scope
$scope.name = user.firstname + ' ' + user.lastname;
});
// different event names let you group your code and logic by what happened
$scope.$on('user:logout', function(event,data) {
.. do something differently entirely ..
});
}]);
其中一个好处是消除了多个手表。 如果你要合并字段或者像上面的例子那样得到值,你必须同时观察名字和姓氏属性。 只有用户对象在更新时被替换,才能使用getUser()函数,如果用户对象仅更新其属性,则不会触发。 在这种情况下,你必须进行深入观察,这是更密集的。
$ broadcast将消息从调用的范围发送到任何子范围。 所以从$ rootScope调用它将在每个范围上触发。 例如,如果您要从控制器的作用域进行广播,则只会在继承自控制器作用域的作用域中触发。 $ emit的方向相反,其行为与DOM事件类似,因为它会激发范围链。
请记住,有些情况下$广播很有意义,有些情况下$ watch是更好的选择 - 尤其是在具有非常特定的观看表达式的隔离范围内时。
我使用类似的方法作为@dtheodot,但使用角度承诺而不是传递回调
app.service('myService', function($q) {
var self = this,
defer = $q.defer();
this.foo = 0;
this.observeFoo = function() {
return defer.promise;
}
this.setFoo = function(foo) {
self.foo = foo;
defer.notify(self.foo);
}
})
然后,只要使用myService.setFoo(foo)
方法来更新服务上的foo
。 在你的控制器中,你可以使用它:
myService.observeFoo().then(null, null, function(foo){
$scope.foo = foo;
})
then
前两个参数是成功和错误回调,第三个是通知回调。
参考$ q。
链接地址: http://www.djcxy.com/p/77851.html