AngularJS - 如何强制范围更新(对数组项的承诺)

时间:2013-01-14 05:09:54

标签: angularjs

我在Angular中创建了一个看起来像这样的控制器(为简洁而编辑):

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

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

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()请求成功),$scope.projects中的AppCtrl已正确更新(项目数组)但$scope.project中的ProjectCtrl 更新。我可以在array[i]函数中记录updateObjectInArray(),它会准确记录我的预期,并且我可以在$scope.projects中记录AppCtrl,它会相应更新,但是当我尝试时要在我的$scope.project控制器中记录ProjectCtrl不会相应更新。

我认为原因是因为我在更新$rootScope.$apply()中的$rootScope.$digest()对象后不得不拨打array[i]updateObjectInArray(),但是,我收到的错误是{{ 1}}。

我需要做些什么来确保我的$digest is already in progress中的数组中的$scope.project项目得到更新?我是否需要为此解决新的承诺?

2 个答案:

答案 0 :(得分:14)

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

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

无论如何,我也相信您可能希望更改 $scope.project if(array[i] == object) {以及您的平等比较({{1} })严格的相等比较(if(array[i]._id === object._id) {。这个==更适合您的原因,因为新创建的对象与旧对象不同。

答案 1 :(得分:3)

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

要求因为你正在返回,并且承诺永远不会被它的结果改变,尽管你可以将promises直接绑定到期望它的内容的HTML。这是因为,在内部,Angular似乎注意到它的结果。

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