I've encounter a strange behavior happening in an Angular's directive I don't understand at all; let me just explain it using code, I think is the easiest way.
What does work:
.directive('myDirective', function ($http) {
return {
template: '...',
link: function (scope, elem, attrs) {
function getData() {
console.log('Starting...');
$http.get(...).success(/* update the template */);
}
getData();
}
};
});
What does not:
.directive('myDirective', function ($http) {
return {
template: '...',
link: function (scope, elem, attrs) {
function getData() {
console.log('Starting...');
$http.get(...).success(/* update the template */);
}
scope.$on('callMyDirective', getData);
}
};
});
The $http call is complete ignored in the second example, not even printing a thing in the finally() part of the promise (there is indeed no network activity), while the log is properly printed in both cases (in the second case, of course, after triggering the event, by clicking a button).
Any clue?
Thanks a lot.
Update:
I found the source of the error, but it is in turn another problem. The thing is that I have an Interceptor where I wrap all the requests but the one which is supposed to authenticate the user with a promise, which I resolve only once the authentication ends. So my interceptor looks like this:
request: function (config) {
if (userHasArrived || isAuthUrl) {
return config || $q.when(config);
}
var defer = $q.defer();
$rootScope.$on('user_logged_in', function (user) {
console.log('User logged in');
userHasArrived = true;
defer.resolve(config);
});
return defer.promise;
}
At the same time, I have a service that runs the auth request, and broadcast the event shown above on success. This is working for all the other requests but for the one I have the directive I mentioned above, which is in a different "page", and never receives the event in the Interceptor (the log never gets printed).
Only when I force a second request to my "auth" URL, the event is received, and the directive stuff works without problems. Could it be that the services is loaded before the interceptor somehow? And in that case, is there a way to control this load order?
Update:
Ok, sorry for bothering you, but if someone is still interested, I found the solution to the second problem. This was the order in which things were happening:
- Authentication request starts
- Authentication request ends, success is broadcasted
- Directive request starts (on demand, clicking a button)
- Authentication success starts to being listened
So the event was being fired before anyone listened to it. This would be the final code (an incomplete version of it):
$rootScope.$on('user_logged_in', function (user) {
userHasArrived = true;
});
return {
request: function (config) {
if (userHasArrived || isAuthUrl) {
return config || $q.when(config);
}
var defer = $q.defer();
var $off = $rootScope.$on('user_logged_in', function (user) {
userHasArrived = true;
$off(); // You better unsubscribe for the events too, if you do something along this lines
defer.resolve(config);
});
return defer.promise;
}
};