7

次のようなコントローラーを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 に基づいてプロジェクトの配列から 1 つのプロジェクトを選択する、次のような別のコントローラーを作成しました。

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.projectsinAppCtrlは正しく更新されますが (プロジェクトの配列)、$scope.projectinProjectCtrlは更新されませんarray[i]関数内にログインupdateObjectInArray()すると、期待どおりにログが記録され、ログイン$scope.projectsするとそれに応じて更新されますが、コントローラーAppCtrlにログインしようとすると、それに応じて更新されません$scope.projectProjectCtrl

その理由は、を呼び出さなければならなかった$rootScope.$apply()か、 でオブジェクト$rootScope.$digest()を更新した後であると思ったのですが、.array[i]updateObjectInArray()$digest is already in progress

$scope.project配列内のアイテムが で更新されるようにするにはどうすればよいProjectCtrlですか? そのための新しい約束を解決する必要がありますか?

4

2 に答える 2

14

が読み込まれるとすぐにprojects、 array の項目の 1 つを使用しています。理論的には、それがメモリ内projects[i]のオブジェクトであると仮定しましょう。0x1問題は、新しい項目が読み込まれ ( と仮定しましょう0x2)、配列を更新すると、配列の位置 ( 0x1) に存在するオブジェクトを変更しているに$scope.projectもかかわらず、現在は放棄された object を参照しているということ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はあなたの目的により適しています。

于 2013-01-15T12:05:36.053 に答える
3

$scope.projectsバインディングでを使用していますか? それともコードのどこかで?

あなたが戻ってきたので質問し、プロミスはその結果によって変更されることはありませんが、プロミスをHTMLに直接バインドしてコンテンツを期待することはできます. これは、内部的に、Angular がその結果を監視しているように見えるために発生します。

したがって、この変数を別の場所で使用している場合は、 を使用する必要があります$q.when($scope.projects)。すでに解決されている場合は、すぐに解決される新しい約束を取得します。

于 2013-01-14T08:46:32.220 に答える