1

I have two controllers that communicate with each other.

Controller 1:

$scope.$on("reloadUsers", function (event) {
        $http.get("/users").success(function(data) {
            $scope.users = data;
            console.log($scope.users);
        });
    });

$http.get("/users").success(function(data) {
    $scope.users = data;
});

Controller 2:

$scope.editUser = function(id){
        $http({
            url: "/users/"+ id,
            method: "PUT",
            data: {
                "firstName":$scope.user.firstName,
                "lastName": $scope.user.lastName,
            }
        });

        $scope.$emit("reloadUsers");
}

My templates are as shown below (both modal dialogs):

Template 1:

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"  ng-controller="Controller 1">

<div ng-repeat="user in users>
    <a data-toggle="modal" data-target="#configureUserModal" href="#" ng-click="getUserId(user.id)" data-id="user.id">{{user.first_name + ' ' +user.last_name}}</a>
</div>

</div>

Template 2:

<div ng-controller="Controller2" class="modal fade" id="configureUserModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">

<label for="">First Name:</label>
<input type="text" value="{{userData.first_name}}" ng-model="user.first_name" />

<label for="">Last Name:</label>
<input type="text" value="{{userData.last_name}}" ng-model="user.last_name"  />

<button type="button" class="btn btn-default" ng-click="editUser(userData.id)" data-dismiss="modal">Save</button>

</div>

Essentially Template 1 has a list of users that I get from Controller 1's scope. On clicking a user in Template 1, I go to Template 2 which displays the user and has an option to edit (change first name and last name). Once I hit Save, I make a HTTP PUT request, save the data, close the modal windows and call emit.

The problem is: When I open Template 1 after this, I see the old first name and last name (not the updated ones). But when I click on the user to open Template 2, the updated names are shown. How do I ensure the data is updated in Template 1? Isn't angular supposed to update it when it sees a change in the $scope variable?

geekchic
  • 2,371
  • 4
  • 29
  • 41
  • 1
    try emitting your event in the success method of your http request. i think its an async problem. – Raphael Müller Dec 16 '14 at 07:35
  • @RaphaelMüller tried that, didn't work unfortunately. When I log `$scope.users` after the emit, it shows the updated data! But it doesn't show up in `Template 1` :/ – geekchic Dec 16 '14 at 07:44
  • What happens when you just call your `$http.put()` and do not call `$emit()` just after? – Kutyel Dec 16 '14 at 07:51
  • @Kutyel Well this is embarrassing, but even without the `$emit()` it works exactly the same :/ – geekchic Dec 16 '14 at 07:56
  • Should I be using a `$watch` function on `$scope.users`? – geekchic Dec 16 '14 at 08:02
  • hm, normally you don't have to, just return the data back to your scope. maybe I'll have my example in a fiddle somewhere (I also have a list and a modal to edit data) – Raphael Müller Dec 16 '14 at 08:04
  • @RaphaelMüller That would be amazing, thank you! – geekchic Dec 16 '14 at 08:05
  • I'm still searching... but have a look at the modal section on http://angular-ui.github.io/bootstrap, you'll see how the value is passed back from the modal on close. – Raphael Müller Dec 16 '14 at 08:15
  • possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – hon2a Dec 16 '14 at 08:27

2 Answers2

1

I finally figured it out after a good deal of refactoring. First, I implemented a service to get my list of users.

angular.module('app').factory('usersService', function($http) {

    var usersService = {
        getUsers: function () {
            return $http.get("/users/").then(function (response) {
                return response.data;
            });
        }
    };

    return usersService;

});

I used then because the HTTP GET request is asynchronous, but I can't display my list of users until the response data is received.

Then in Controller 1, I added in these bits of code:

    $scope.users = usersService;

    usersService.getUsers().then(function (asyncUsers) {
        $scope.users = asyncUsers;
    });

    $scope.$watch('users', function (users) {
        if (angular.isDefined(users)) {
            console.log("$scope.users has data");
        }
    });

    $scope.$on("reloadUsers", function (event) {
        usersService.getUsers().then(function (asyncUsers) {
            $scope.users = asyncUsers;
        });
    });

In here, I basically just call the service and wait for $scope.users to gets it value. To find out exactly when that happens, I just have a $scope.watch function in there as well. I also have a function that waits for the reloadUsers event emitted from Controller 2 which refreshes the data in $scope.users.

And finally, in Controller 2, I have:

$scope.editUser = function(id){
        $http({
            url: "/user/"+ id,
            method: "PUT",
            data: {
                "firstName": $scope.user.firstName,
                "lastName": $scope.user.lastName,
            }
            }).success (function(data) {
                $scope.$emit("reloadUsers");
        });
    }

Just calling $scope.emit to indicate that it's time to refresh. So I'm pretty sure my problem was the lack of communication between controllers since I hadn't used a service, as well as the asynchronous GET requests. This solution resolves both!

geekchic
  • 2,371
  • 4
  • 29
  • 41
0

I would try rewriting the following code:

$scope.editUser = function(id){
    $http.put("/users/" + id, 
    {
        firstName: $scope.user.firstName,
        lastName: $scope.user.lastName
    })
    .success(function(){
        $scope.$emit("reloadUsers");
    });
}

Hope it works!

EDIT:

Custom update method.

angular.module('unknown', ['ngResource'])
.factory('Users', ['$resource', function($resource){
    return $resource('/users/:id', { id:'@id' }, {
      update: { method: 'PUT' },
      get: { method: 'GET' }
    });
}]);
Kutyel
  • 8,575
  • 3
  • 30
  • 61
  • Thanks for this, but I tried the same thing when Raphael suggested it and it didn't work :( – geekchic Dec 16 '14 at 08:04
  • Aw, you're too kind. Don't be sorry! Thanks for trying to help. I'm going to play around with `$watch` and `$digest` to see if that works. – geekchic Dec 16 '14 at 08:06
  • Hmmm, that's an idea. I'm going to try that out as well. – geekchic Dec 16 '14 at 08:09
  • I completely refactored my code, using elements from your answer and it finally works! Going to put my solution in here as well. – geekchic Dec 16 '14 at 10:43