geekchic
geekchic

Reputation: 2451

Template doesn't render reloaded data: AngularJS

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?

Upvotes: 1

Views: 419

Answers (2)

Kutyel
Kutyel

Reputation: 9094

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' }
    });
}]);

Upvotes: 0

geekchic
geekchic

Reputation: 2451

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!

Upvotes: 1

Related Questions