更改服务数据时更新范围值 [英] Update scope value when service data is changed

查看:21
本文介绍了更改服务数据时更新范围值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用中有以下服务:

uaInProgressApp.factory('uaProgressService',功能(uaApiInterface,$超时,$rootScope){var 工厂 = {};factory.taskResource = uaApiInterface.taskResource()factory.taskList = [];factory.cron = 未定义;factory.updateTaskList = function() {factory.taskResource.query(function(data){factory.taskList = 数据;$rootScope.$digest控制台日志(工厂任务列表);});factory.cron = $timeout(factory.updateTaskList, 5000);}factory.startCron = 函数 () {factory.cron = $timeout(factory.updateTaskList, 5000);}factory.stopCron = 函数 (){$timeout.cancel(factory.cron);}返厂;});

然后我在这样的控制器中使用它:

uaInProgressApp.controller('ua.InProgressController',函数 ($scope, $rootScope, $routeParams, uaContext, uaProgressService) {uaContext.getSession().then(function(){uaContext.appName.set('测试屋');uaContext.subAppName.set('进行中');uaProgressService.startCron();$scope.taskList = uaProgressService.taskList;});});

所以基本上我的服务每 5 秒更新一次 factory.taskList,我将这个 factory.taskList 链接到 $scope.taskList.然后我尝试了不同的方法,例如 $apply$digest,但是 factory.taskList 上的更改没有反映在我的控制器和视图中 $scope.taskList.

它在我的模板中仍然是空的.您知道我如何传播这些更改吗?

解决方案

虽然使用 $watch 可以解决问题,但这并不是最有效的解决方案.您可能希望更改在服务中存储数据的方式.

问题在于,每次为 taskList 分配新值时,您都在替换与它关联的内存位置,而作用域却卡在指向旧位置.您可以在这个 plunk 中看到这种情况.

首次加载 plunk 时,使用 Chrome 拍摄堆快照,单击按钮后,您将看到范围指向的内存位置从未更新,而列表指向不同的内存位置.

您可以通过让您的服务持有一个包含可能发生变化的变量的对象来轻松解决此问题(例如 data:{task:[], x:[], z:[]}).在这种情况下,永远不应更改数据",但您可以随时更改其任何成员.然后将此数据变量传递给作用域,只要您不通过尝试将数据"分配给其他内容来覆盖它,只要数据中的字段发生更改,作用域就会知道它并正确更新.

这个 plunk 显示了使用上面建议的修复程序运行的相同示例.在这种情况下不需要使用任何观察者,如果发生视图上的某些内容没有更新,您知道您需要做的就是运行范围 $apply 来更新视图.

通过这种方式,您无需频繁比较变量变化的观察者,以及在需要观察许多变量的情况下所涉及的丑陋设置.这种方法的唯一问题是,在您的视图 (html) 中,您将拥有数据".在您过去只使用变量名称的所有内容添加前缀.

I have the following service in my app:

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

Then I use it in a controller like this:

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

So basically my service update factory.taskList every 5 seconds and I linked this factory.taskList to $scope.taskList. I then tried different methods like $apply, $digest but changes on factory.taskList are not reflected in my controller and view $scope.taskList.

It remains empty in my template. Do you know how I can propagate these changes ?

解决方案

While using $watch may solve the problem, it is not the most efficient solution. You might want to change the way you are storing the data in the service.

The problem is that you are replacing the memory location that your taskList is associated to every time you assign it a new value while the scope is stuck pointing to the old location. You can see this happening in this plunk.

Take a heap snapshots with Chrome when you first load the plunk and, after you click the button, you will see that the memory location the scope points to is never updated while the list points to a different memory location.

You can easily fix this by having your service hold an object that contains the variable that may change (something like data:{task:[], x:[], z:[]}). In this case "data" should never be changed but any of its members may be changed whenever you need to. You then pass this data variable to the scope and, as long as you don't override it by trying to assign "data" to something else, whenever a field inside data changes the scope will know about it and will update correctly.

This plunk shows the same example running using the fix suggested above. No need to use any watchers in this situation and if it ever happens that something is not updated on the view you know that all you need to do is run a scope $apply to update the view.

This way you eliminate the need for watchers that frequently compare variables for changes and the ugly setup involved in cases when you need to watch many variables. The only issue with this approach is that on your view (html) you will have "data." prefixing everything where you used to just have the variable name.

这篇关于更改服务数据时更新范围值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆