我有一个服务,说:
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。我已经拼凑了这个模式,其中我添加aService到控制器的$scope,然后使用$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;
}
});
}
这感觉有点冗长,我一直在每个使用服务变量的控制器中重复这一点。有没有更好的方法来监视共享变量?
这是我的一般方法。
mainApp.service('aService',[function(){
var self = this;
var callbacks = {};
this.foo = '';
this.watch = function(variable, callback) {
if (typeof(self[variable]) !== 'undefined') {
if (!callbacks[variable]) {
callbacks[variable] = [];
}
callbacks[variable].push(callback);
}
}
this.notifyWatchersOn = function(variable) {
if (!self[variable]) return;
if (!callbacks[variable]) return;
angular.forEach(callbacks[variable], function(callback, key){
callback(self[variable]);
});
}
this.changeFoo = function(newValue) {
self.foo = newValue;
self.notifyWatchersOn('foo');
}
}]);
在控制器中
function FooCtrl($scope, aService) {
$scope.foo;
$scope._initWatchers = function() {
aService.watch('foo', $scope._onFooChange);
}
$scope._onFooChange = function(newValue) {
$scope.foo = newValue;
}
$scope._initWatchers();
}
FooCtrl.$inject = ['$scope', 'aService'];
当我面对一个非常相似的问题时,我观察了一个作用域中的函数,并让函数返回服务变量。我已经创建了一个js小提琴。您可以在下面找到代码。
var myApp = angular.module("myApp",[]);
myApp.factory("randomService", function($timeout){
var retValue = {};
var data = 0;
retValue.startService = function(){
updateData();
}
retValue.getData = function(){
return data;
}
function updateData(){
$timeout(function(){
data = Math.floor(Math.random() * 100);
updateData()
}, 500);
}
return retValue;
});
myApp.controller("myController", function($scope, randomService){
$scope.data = 0;
$scope.dataUpdated = 0;
$scope.watchCalled = 0;
randomService.startService();
$scope.getRandomData = function(){
return randomService.getData();
}
$scope.$watch("getRandomData()", function(newValue, oldValue){
if(oldValue != newValue){
$scope.data = newValue;
$scope.dataUpdated++;
}
$scope.watchCalled++;
});
});
你可以在$rootScope中插入服务,然后观察:
myApp.run(function($rootScope, aService){
$rootScope.aService = aService;
$rootScope.$watch('aService', function(){
alert('Watch');
}, true);
});
在你的控制器中:
myApp.controller('main', function($scope){
$scope.aService.foo = 'change';
});
另一个选择是使用外部库,例如:https://github.com/melanke/Watch.JS
"发射架:IE +, f4 +,稳定基金5+
您可以观察一个、多个或所有对象属性的变化。
例子:
var ex3 = {
attr1: 0,
attr2: "initial value of attr2",
attr3: ["a", 3, null]
};
watch(ex3, function(){
alert("some attribute of ex3 changes!");
});
ex3.attr3.push("new value");
如果您想避免$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
};
有点丑,但我已经为切换添加了范围变量的注册到我的服务:
myApp.service('myService', function() {
var self = this;
self.value = false;
self.c2 = function(){};
self.callback = function(){
self.value = !self.value;
self.c2();
};
self.on = function(){
return self.value;
};
self.register = function(obj, key){
self.c2 = function(){
obj[key] = self.value;
obj.$apply();
}
};
return this;
});
然后在控制器中:
function MyCtrl($scope, myService) {
$scope.name = 'Superhero';
$scope.myVar = false;
myService.register($scope, 'myVar');
}
看看这个活塞:这是我能想到的最简单的例子?
http://jsfiddle.net/HEdJF/
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<input type="text" ng-model="Data.FirstName"><!-- Input entered here -->
<br>Input is : <strong>{{Data.FirstName}}</strong><!-- Successfully updates here -->
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{Data.FirstName}}<!-- How do I automatically updated it here? -->
</div>
</div>
// declare the app with no dependencies
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
return { FirstName: '' };
});
myApp.controller('FirstCtrl', function( $scope, Data ){
$scope.Data = Data;
});
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.Data = Data;
});