I'm having an issue with custom directives that's driving me crazy. I'm trying to create the following custom (attribute) directive:
angular.module('componentes', [])
.directive("seatMap", function (){
return {
restrict: 'A',
link: function(scope, element, attrs, controller){
function updateSeatInfo(scope, element){
var txt = "";
for (var i in scope.seats)
txt = txt + scope.seats[i].id + " ";
$(element).text("seat ids: "+txt);
}
/*
// This is working, but it's kind of dirty...
$timeout(function(){updateSeatInfo(scope,element);}, 1000);
*/
scope.$watch('seats', function(newval, oldval){
console.log(newval, oldval);
updateSeatInfo(scope,element);
});
}
}
});
This "attribute-type" directive (called seatMap) is trying to show a list of seat ids (e.g, for a theatre) which I'll fetch from the server via $resource service (see code below) into a div (element).
I'm using it with this simple partial html:
<div>
<!-- This is actually working -->
<ul>
<li ng-repeat="seat in seats">{{seat.id}}</li>
</ul>
<!-- This is not... -->
<div style="border: 1px dotted black" seat-map></div>
</div>
And this is the controller which is loading the scope:
function SeatsCtrl($scope, Seats) {
$scope.sessionId = "12345";
$scope.zoneId = "A";
$scope.seats = Seats.query({sessionId: $scope.sessionId, zoneId: $scope.zoneId});
$scope.max_seats = 4;
}
Where "Seats" is a simple service using $resources to fetch a JSON from the server
angular.module('myApp.services', ['ngResource'])
.factory('Seats', function($resource){
return $resource('json/seats-:sessionId-:zoneId.json', {}, {});
})
;
app.js (asientos_libres.html is the partial I've been using):
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'componentes']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/asientos_libres.html', controller: SeatsCtrl});
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
The problem is, even though I set up a "scope.$watch" in the link function of the directive so that the scope can check whether "seats" attribute has changed to update the list of ids, it isn't working at the moment $scope.seats is changing in the controller (when we call "query").
As you might see in the code, I made a try using $timeout to delay the launch of "updateSeatInfo", but I'm afraid it's not the smartest solution by far...
I also tried to not to make a JSON request, but use a hard-coded dictionary in $scope.seats and it works, so it seems it's a matter of synchrony.
Note: The updateSeatInfo is just a test function, the actual function I'll use is a bit more complex.
Any idea about how to cope with it?
Thank you a lot beforehand!
Edit 1: Added app.js, where I'm using router to call SeatsCtrl, thanks to Supr for the advice. However, I'm still having the same issue.
Edit 2: Solved!(?) Ok! It seems I found a solution, which may not be the best, but it's working properly! :) As far as I could see here http://docs.angularjs.org/api/ng.$timeout, we can use $timeout (a wrapper over setTimeout) with no delay! This is great because we aren't artificially delaying the execution of our code inside $timeout, but we're making the directive not to run it until the asynchronous request has finished.
Hope it will work for long-wait requests, too...
If someone knows a better way to fix it, please tell!
The issue is that watch compares the reference instead of the object by default. Add ,true to the end to have it compare the value instead.
scope.$watch('seats', function(newval, oldval){
console.log(newval, oldval);
updateSeatInfo(scope,element);
}, true);