更改服务数据时更新范围值

我在我的应用程序中有以下服务:

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; }); } ); 

所以基本上我的服务更新factory.taskList每5秒钟,我把这个factory.taskList链接到$scope.taskList 。 然后我尝试了不同的方法,如$apply$digest但对factory.taskList变化不反映在我的控制器和查看$scope.taskList

它在我的模板中仍然是空的。 你知道我怎么能传播这些变化吗?

虽然使用$watch可能会解决问题,但这不是最有效的解决scheme。 您可能想要更改在服务中存储数据的方式。

问题是,你正在replace你的taskList关联的内存位置,每次你指定一个新的值,而范围卡住指向旧的位置。 你可以看到这发生在这个庞然大物 。

当你第一次加载plunk时,使用Chrome浏览器获取堆快照,点击button后,你会发现当列表指向不同的内存位置时,范围指向的内存位置永远不会更新。

你可以通过让你的服务持有一个包含可能改变的variables的对象(如data:{task:[], x:[], z:[]} )来轻松解决这个问题。 在这种情况下,“数据”不应该改变,但是其中的任何一个成员都可以随时更改。 然后,您将这个数据variables传递给作用域,只要您不试图将“数据”分配给其他数据,只要数据中的某个字段发生更改,作用域就会知道该数据并将正确更新。

这个plunk显示了使用上面build议的修复运行的同一个例子。 在这种情况下,不需要使用任何观察者,如果发生某些事情没有在视图上更新,则您只需运行一个作用域$apply来更新视图。

通过这种方式,您不再需要频繁比较variables的观察者,而需要观察许多variables的情况下需要使用丑陋的设置。 这个方法唯一的问题就是在你的视图(html)上你会有“数据”。 在你刚刚使用variables名的地方添加前缀。

Angular(不像Ember和其他一些框架)不提供特别包装的对象,它们半神奇地保持同步。 你正在操作的对象是纯javascript对象,就像说var a = b;链接variablesab ,说$scope.taskList = uaProgressService.taskList不链接这两个值。

对于这种linkangular$scope上提供$watch 。 您可以观察uaProgressService.taskList的值,并在更改时更新$scope的值:

 $scope.$watch(function () { return uaProgressService.taskList }, function (newVal, oldVal) { if (typeof newVal !== 'undefined') { $scope.taskList = uaProgressService.taskList; } }); 

传递给$watch函数的第一个expression式在每个$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。

不需要$watch等。 您可以简单地定义以下内容

 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.getTaskList = function() { return uaProgressService.taskList; }; }); 

由于函数getTaskList属于$scope ,因此每次更改uaProgressService.taskList都会计算(更新)返回值

轻量级的select是在控制器初始化期间,您订阅服务中设置的通知程序模式。

就像是:

 app.controller('YourCtrl'['yourSvc', function(yourSvc){ yourSvc.awaitUpdate('YourCtrl',function(){ $scope.someValue = yourSvc.someValue; }); }]); 

而服务有这样的东西:

 app.service('yourSvc', ['$http',function($http){ var self = this; self.notificationSubscribers={}; self.awaitUpdate=function(key,callback){ self.notificationSubscribers[key]=callback; }; self.notifySubscribers=function(){ angular.forEach(self.notificationSubscribers, function(callback,key){ callback(); }); }; $http.get('someUrl').then( function(response){ self.importantData=response.data; self.notifySubscribers(); } ); }]); 

当您的控制器从服务中刷新时,这可以让您更仔细地进行微调。

就像Gabriel Piacenti所说的,如果你把变化的数据包装成一个物体,就不需要手表了。

但是为了正确更新范围内已更改的服务数据,使用服务数据的控制器的范围值不直接指向正在更改的数据(字段)是很重要的。 相反,范围值必须指向包装不断变化的数据的对象。

下面的代码应该更清楚地解释这一点。 在我的例子中,我使用NLS服务进行翻译。 NLS令牌正在通过http更新。

服务:

 app.factory('nlsService', ['$http', function($http) { var data = { get: { ressources : "gdc.ressources", maintenance : "gdc.mm.maintenance", prewarning : "gdc.mobMaint.prewarning", } }; // ... asynchron change the data.get = ajaxResult.data... return data; }]); 

控制器和范围expression式

 app.controller('MenuCtrl', function($scope, nlsService) { $scope.NLS = nlsService; } ); <div ng-controller="MenuCtrl"> <span class="navPanelLiItemText">{{NLS.get.maintenance}}</span> </div> 

上面的代码工作,但首先我想直接访问我的NLS令牌(见下面的代码片段),这里的值没有更新。

 app.controller('MenuCtrl', function($scope, nlsService) { $scope.NLS = nlsService.get; } ); <div ng-controller="MenuCtrl"> <span class="navPanelLiItemText">{{NLS.maintenance}}</span> </div>