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

win*_*toy 7 angularjs

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

function AppCtrl($scope, $http, $location, $dataService) {
    $scope.projects = $dataService.data.projects;
}
Run Code Online (Sandbox Code Playgroud)

这正确加载了$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) {});
    };

});
Run Code Online (Sandbox Code Playgroud)

我创建了另一个看起来像这样的控制器,它根据当前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];
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

当我尝试运行我的updateObjectInArray()功能(我的成功$http.put()要求),我$scope.projectsAppCtrl正确更新(项目的阵列),但我$scope.projectProjectCtrl更新.我可以登录array[i]的内部updateObjectInArray()功能,它会记录正是我期待的,我可以登录$scope.projectsAppCtrl,它会相应地更新,但是当我尝试登录$scope.project我的ProjectCtrl控制器,它不会随之更新.

我认为原因是因为我不得不打电话$rootScope.$apply()或者$rootScope.$digest()在我更新了array[i]对象之后updateObjectInArray(),然而,我得到了错误$digest is already in progress.

我需要做些什么来确保我$scope.project的数组中的项目在我的更新ProjectCtrl?我是否需要为此解决新的承诺?

Cai*_*nha 14

一旦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更适合您的原因,因为新创建的对象与旧对象不同.