我的应用程序中有以下服务:
uaInProgressApp.factory('uaProgressService',
function(uaApiInterface, $timeout, $rootScope){
var factory = {};
factory.taskResource = uaApiInterface.taskResource()
factory.taskList = [];
factory.cron = undefined;
factory.updateTaskList = function() {
factory.taskResource.query(function(data){
factory.taskList = data;
$rootScope.$digest
console.log(factory.taskList);
});
factory.cron = $timeout(factory.updateTaskList, 5000);
}
factory.startCron = function () {
factory.cron = $timeout(factory.updateTaskList, 5000);
}
factory.stopCron = function (){
$timeout.cancel(factory.cron);
}
return factory;
});
然后我在控制器中这样使用它:
uaInProgressApp.controller('ua.InProgressController',
function ($scope, $rootScope, $routeParams, uaContext, uaProgressService) {
uaContext.getSession().then(function(){
uaContext.appName.set('Testing house');
uaContext.subAppName.set('In progress');
uaProgressService.startCron();
$scope.taskList = uaProgressService.taskList;
});
}
);
因此,我的服务基本上每 5 秒更新一次 factory.taskList
,我将这个 factory.taskList
链接到了 $scope.taskList
。然后我尝试了不同的方法,如 $apply
、$digest
,但 factory.taskList
上的更改并没有反映到我的控制器和视图 $scope.taskList
。
它在我的模板中仍然是空的。您知道如何传播这些更改吗?
虽然使用 $watch
可以解决问题,但这并不是最有效的解决方案。您可能需要改变在服务中存储数据的方式。
问题在于,每次为 taskList
赋新值时,您都在替换与之关联的内存位置,而作用域却仍然指向旧位置。您可以在 this plunk 中看到这种情况。
在第一次加载 plunk 时使用 Chrome 浏览器拍摄堆快照,点击按钮后,您会发现作用域指向的内存位置从未更新,而列表指向的内存位置却不同。
您可以让您的服务持有一个包含可能发生变化的变量的对象(类似于 data:{task:[],x:[],z:[]}
),从而轻松解决这个问题。在这种情况下,"data"永远不会被更改,但其中的任何成员都可以随时更改。然后,您将此 data 变量传递给作用域,只要您不试图将 "data" 赋值给其他内容而覆盖它,只要 data 中的字段发生变化,作用域就会知道并正确更新。
本 plunk 展示了使用上述修复方法运行的相同示例。在这种情况下无需使用任何监视器,而且如果视图上的某些内容没有更新,您只需运行作用域 $apply
来更新视图即可。
这样,您就不需要经常比较变量变化的观察者,也不需要在需要观察许多变量时进行难看的设置。这种方法的唯一问题是,在您的视图(html)中,您将在所有内容前加上"data."前缀,而以前您只需输入变量名即可。
Angular(与 Ember 和其他一些框架不同)不提供特殊的_wrapped_对象,这些_wrapped_对象会_半魔术般地_保持同步。您正在操作的对象是普通的 javascript 对象,就像说 var a = b;
并不能_链接变量 a
和 b
一样,说 $scope.taskList = uaProgressService.taskList
也不能链接这两个值。
对于这种链接,angular
提供了 $scope
上的 $watch
。您可以观察 uaProgressService.taskList
的值,并在其发生变化时更新 $scope
上的值:
$scope.$watch(function () { return uaProgressService.taskList }, function (newVal, oldVal) {
if (typeof newVal !== 'undefined') {
$scope.taskList = uaProgressService.taskList;
}
});
传递给 $watch
函数的第一个表达式将在每次 $digest
循环时执行,第二个参数是使用新值和旧值调用的函数。
我不知道这是否有用,但我正在做的是将函数绑定到 $scope.value。例如
angular
.module("testApp", [])
.service("myDataService", function(){
this.dataContainer = {
valA : "car",
valB : "bike"
}
})
.controller("testCtrl", [
"$scope",
"myDataService",
function($scope, myDataService){
$scope.data = function(){
return myDataService.dataContainer;
};
}]);
然后在 DOM 中将其绑定为
<li ng-repeat="(key,value) in data() "></li>
这样就可以避免在代码中使用 $watch。