简体   繁体   中英

AngularJS: scope not updating in template after ajax call

I have this array of objects :

$scope.posts = [
    { 
        "name" : "name1",
        "age" : 12
    },
    { 
        "name" : "name1",
        "age" : 13
    },
    { 
        "name" : "name1",
        "age" : 14
    }
]

I am ng-repeating this array in my markup as follows:

<div ng-repeat="post in posts">
    <span>{{post.name}}</span>
    <button ng-click="editPost(post)">Click!</button> <!-- passing post as argument here-->
</div>

Controller:

app.controller('PostController', function($scope, postFactory){
    //array is present in controller, just not showing it here
    $scope.editPost = function(post) {
        postFactory.editPost(post).then(function(data) { //factory having an ajax call which gets new data to be assigned to 'post'
            post = angular.copy(data.data)
            console.log(post); //here new data is populated successfully
        })
    }
})

As you can see, when 'editPost' is called, new post data is fetched from an API via a factory and assigned to 'post'(which is the argument to the 'editPost' function). When I console log 'post' after it is assigned the new data, it shows the new data in the console. HOWEVER, in my markup, still the old data is displayed. Any idea why the markup isn't updated? Here's my factory:

app.factory('postFactory', function($http) {
    return {
        editPost : editPost
    }

    function editPost(post) {
        return $http.post('<api>', post).success(function(response) {
            return response.data;
        })
    }
})

EDIT:

I just noticed something. When I changed:

post = angular.copy(data.data)

to

post.name = data.data.name;

the post gets updated. So, I am guessing mass assignment of an object is not getting updated but when I update an individual property, it gets updated in the template.

Short answer: References are "passed by value" to functions.

Long answer:

When you're passing an object to a function, the function will receive a copy of a reference to that object. When you overwrite that reference, the results will only be visible in the scope of that function.

In other words, when you're doing:

post = angular.copy(data.data)

You're only changing the thing that post (inside of editPost ) is pointing to. This will have no effect on the outside world/scope (when I say scope, I mean the normal JS function scope, not Angular's scope).

One possible way to make your code work is to pass the $index value to editPost and then modify $scope.posts like this:

$scope.editPost = function(index) {
        postFactory.editPost($scope.posts[index]).then(function(data) { 
            $scope.posts[index]= angular.copy(data.data)
        })
    }

EDIT:

Since my explanation wasn't clear enough I'll try to elaborate.

Imagine that you have an object in memory. Let's call this object objInMem . This object is referenced by vars . In essence, a var is like an arrow, pointing to some place in memory, the place where our object is.

someVar -> objInMem

Of course the value of that reference (the "address" of the object) is also in memory and can be copied by assiging it to other vars .

var otherVar = someVar; // someVar -> objInMem <- otherVar

When you invoke a function that takes an object, JS will copy the value of the reference that you passed and "give" that copy to the function.

function f(obj) {...}
f(someVar); // someVar -> objInMem <- obj (inside function f)

When you try to assign something else to obj (inside of f), it just changes the value of that reference,But the original reference will remain unchanged:

obj = someOtherThing; // obj -> someOtherThingInMem

// someVar -> objInMem (still the same)

I hope this clears things up. It's a bit oversimplified and does not cover simple values (like numbers), but it should explain this specific situation.

Most likely angular is not aware of the asynchronous update.

Try to wrap it in a timeout like so:

$timeout(function(){
  post = angular.copy(data.data)
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM