【问题标题】:AngularJS - how to force a scope to update (promise for array item)AngularJS - 如何强制更新范围(数组项的承诺)
【发布时间】:2013-01-14 05:09:54
【问题描述】:

我在 Angular 中创建了一个如下所示的控制器(为简洁而编辑):

function AppCtrl($scope, $http, $location, $dataService) {
    $scope.projects = $dataService.data.projects;
}

从我的$dataService 服务中正确加载$scope.projects 承诺。

app.service('$dataService', function($q, $http, $location, $rootScope) {
    var dataService = this; //Provides access 'this' inside functions below
    var projectsDeferred = $q.defer();

    $http.get('/api').success(function(data, status, headers, config) {
        projectsDeferred.resolve(data.projects);
    }).error(function(err) {
        projectsDeferred.reject(err);
    });

    this.data = {projects: projectsDeferred.promise};

    //UPDATE FUNCTION
    function updateObjectInArray(array, object, newData) {
        for(i in array) {
            if(array[i] == object) {
                if(newData != undefined) {
                    array[i] = newData;
                } else {
                    return array[i];
                }
            }
        }
        return undefined;
    }


    this.updateProject = function(project, updateData) {
        $http.put('/api/projects/' + project._id, updateData)
            .success(function(data, status, headers, config) {
            updateObjectInArray(dataService.data.projects.$$v, project, data);
        }).error(function(data, status, headers, config) {});
    };

});

我创建了另一个看起来像这样的控制器,它根据当前 URL 从项目数组中选择一个项目:

function ProjectCtrl($scope, $route) {
    //Getting the current project from the array of projects
    $scope.project = $scope.projects.then(function(projects) {
        for(i in projects) {
            if(projects[i]._id == $route.current.params.projectId) {
                return projects[i];
            }
        }
    });
}

当我尝试运行我的updateObjectInArray() 函数时(在我的$http.put() 请求成功时),我在AppCtrl 中的$scope.projects 已正确更新(项目数组)但我在@987654331 中的$scope.project @ 已更新。我可以在updateObjectInArray() 函数中记录array[i],它会准确记录我的期望,我可以在AppCtrl 中记录$scope.projects,它会相应更新,但是当我尝试在我的@ 中记录$scope.project 987654337@ 控制器,它没有相应地更新。

我认为原因是因为我在更新updateObjectInArray() 中的array[i] 对象后必须调用$rootScope.$apply()$rootScope.$digest(),但是,我得到$digest is already in progress 的错误。

我需要做些什么来确保数组中的$scope.project 项目在我的ProjectCtrl 中得到更新?我需要为它解决一个新的承诺吗?

【问题讨论】:

  • 你在哪里调用updateProject?你确定是在解析 $dataService.data.projects 之前吗?尝试在几个函数中添加console.logs
  • 不,我想在解析$dataService.data.projects后调用它。预期的功能是它在页面首次加载时从服务器中提取数据,并且用户可以执行将更新发送到服务器的操作,如果成功,则使用从服务器返回的新数据更新范围。
  • 我的意思是之后:) 还为时过早。
  • 当用户单击按钮时,我在控制器中调用它。是的,我很肯定它已经解决了。正如我所说,我可以在更新对象后记录array[i],并且它已经完全按照我的预期进行了更新,但是记录我的范围显示它还没有更新到$dataService.projects 现在等于。
  • (我的意思是输入$dataService.data.projects

标签: angularjs


【解决方案1】:

一旦projects 被加载,您将使用数组projects[i] 中的一项,理论上假设它是内存中的对象0x1。问题是当一个新项目被加载时(假设0x2),并且您更新了数组,您正在更改驻留在数组位置的对象(0x1),但$scope.project 仍然引用现在废弃的对象0x1。不能只在数组中改,必须修改,所以不需要重新绑定$scope.project变量。

最好的解决方案是更改 array[i] = newData angular.extend(array[i], newData)。这样,您只需更改 array[i] 的所有属性,并且当您的 $scope.project 指向内存中的同一对象时,它将被更新。

无论如何,我也相信你可能想改变 if(array[i] == object) { if(array[i]._id === object._id) { 和你的平等比较(== 严格相等比较 (===)。这个if 更适合您的事业,因为新创建的对象与旧对象不同。

【讨论】:

  • 优秀的答案!非常感谢!我以前从未听说过angular.extend(),但它很好用。这是否比调用$scope.watch('projects', ... 更有效,因为调用$watch 意味着角度必须做更多的工作?关于严格平等的好建议,我将使用它。
  • 这可能最有利于性能,因为您只会在对象更改时合并对象。每个注册的 $watch 都在 any 范围摘要周期上运行。您必须注意使用它的位置,尤其是当您需要递归 $watch 时,这就是您的情况。 angular.extends 几乎是基于 jQuery.extend。随时。
  • 伙计,你无法相信你所做的好事。我把这一切都与绑定和扩展变量混为一谈。非常感谢这并澄清了我的情况。百万谢谢。
  • 我的问题似乎是,如果新对象不包含要覆盖的值,旧属性将不会被清除?
【解决方案2】:

您是否在绑定中使用$scope.projects?还是代码中的其他地方?

因为你正在返回而询问,并且承诺永远不会被它的结果改变,尽管你可以将承诺直接绑定到期望它的内容的 HTML。发生这种情况是因为在内部,Angular 似乎在关注它的结果。

因此,如果您在其他地方使用此变量,则需要使用$q.when($scope.projects)。您将获得一个新的承诺,如果它已经解决,它将立即解决。

【讨论】:

  • 我相信我已经将问题归结为我将它从数组中拉出来的事实。看起来我简化了我的代码太多了。我已经相应地更新了我的问题。请参阅,在AppCtrl 中,$scope.projects 始终正确更新,无需任何额外工作。但是,当我尝试从该数组中拉出单个项目时(在ProjectCtrl 中,它没有更新。是的,顺便说一句,我将它绑定到 HTML 并且当我传递整个数组时它工作得很好. 非常感谢你的帮助,你太棒了。
  • 在下面查看我的答案。我创建了一个新的,因为它太大而无法评论。
猜你喜欢
  • 2012-12-28
  • 1970-01-01
  • 2019-02-10
  • 2014-10-22
  • 1970-01-01
  • 2014-06-24
  • 1970-01-01
  • 2017-04-23
  • 1970-01-01
相关资源
最近更新 更多