Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS directive template not updating if scope is populated via ajax

I tried to give this question as precise a title as I could.
I'm pretty new to AngularJS but I'm stomped on this issue. I tried to make a jsfiddle to better illustrate my issue but it relies on too many separate files. And alas it is not online yet, so bear with the verbosity. :)

So basically I have an app I built with yeoman init angular, and my app.js looks like this:

"use strict"

var myApp = angular.module("myApp", [])
.config(function($routeProvider) {
    $routeProvider
    .when("/lineup", {
        templateUrl: "views/lineup.html",
        controller: "LineupCtrl"
    })
    //other routes
    .otherwise({
        redirectTo: "/"
    });
})
.directive("playerlist", function() {
    return {
        restrict: "E",
        transclude: false,
        scope : {},
        templateUrl : "views/directives/playerlist.html",
        controller : function($scope) {
            $.get("/players")
            .success(function(players) {
                $scope.players = players;
            });
        },
        replace : true
    }
});

My index.html picks up app.js and has an anchor that references #/lineup, which effectively opens views/lineup.html; to simplify things, let's assume the latter only contains the (custom) <playerlist></playerlist> tag.
Inside the directive's controller function I'm sure that $.get("/players") works as it should because I can see from chrome's network tab that the response comes through correctly as an array of players.
Finally, my views/directives/playerlist.html has the code that replaces the <playerlist> tag, which follows:

<table class="table table-striped">
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
            <th>Role</th>
            <th>Strength</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="player in players">
            <td>{{player.first_name}} {{player.last_name}}</td>
            <td>{{player.age}}</td>
            <td>{{player.role}}</td>
            <td>{{player.strength}}</td>
        </tr>
    </tbody>
</table>

My idea was to make the "playerlist" directive independent from LineupCtrl for I might want to reuse it elsewhere in the project.
Ok so here goes: when I click on the anchor that loads #/lineup the first time, the tbody element of the above table is empty (no rows appended to it); the funny thing is, when I click on it a second time, the table is correctly populated with the players I get with the $.get("/players") instruction. I suspect this is due to the slight lag that occurs between the rendering of playerlist.html and the $scope.players variable being assigned. But isn't that the whole point of an angular app? That when scope variables change the respective views (and their templates) are updated?
Please help!
Cheers,

Andrea

like image 289
Andrea Aloi Avatar asked Feb 20 '13 16:02

Andrea Aloi


1 Answers

Whenever you update scope variables outside of an angular function, you need to tell angular that something changed. See scope.$apply.

$.get("/players")
.success(function(players) {
   $scope.$apply(function () {
     $scope.players = players;
   });
});

On a different note, angular has a built in ajax service, so there is no need to use jQuery. A good explanation can be found in the tutorial: 5 - XHRs & Dependency Injection.

like image 192
Yoshi Avatar answered Nov 18 '22 03:11

Yoshi