I started from a demo Ionic app (ionic start myApp sidemenu
), and added a resolve
to one of the views:
resolve: {
issue: function($q, $timeout) {
var defer = $q.defer();
//defer.reject(); // Doesn't work browser or device
$timeout(defer.reject); // Works in browser, but not device
return defer.promise;
}
}
I monitor rejected resolve
s here:
.run(function($ionicPlatform, $rootScope, $ionicLoading) {
$ionicPlatform.ready(function() {
// regular stuff here
$rootScope.$on('$stateChangeError', function() {
$ionicLoading.show({
template: 'All good!'
});
});
});
});
For some reason, if resolve
rejects immediately (see defer.reject()
above), the callback of $stateChangeError
is not run. If I do exactly the same, but outside of Ionic, it works!
Moreover, trying to delay the resolve
rejection by doing $timeout(defer.reject);
results in a different behaviour. Now it works in a browser as expected, but still doesn't work on a device. Trying to delay even more, results in success on device:
$timeout(function() {
defer.reject();
}, 250); // Doesn't work for me with 200 or less
Can anyone shed light on this?
SEE HERE HOW TO REPRODUCE THE ISSUE
From my experience with Angular and the promise model. In order to resolve/reject a promise Angular must tick over one cycle of the JS event loop - nextTick - and this can be accomplished using $scope.apply() which is how we mock such things in unit tests.
This is an awesome article that talks about $timeout and $scope.$evalAsync - from what I can gather $timeout is evaluating the function in the next tick. Which is the reason that this code works the way you outlined.
resolve: {
issue: function($q, $timeout) {
var defer = $q.defer();
//defer.reject(); // <---- no nextTick
$timeout(defer.reject); // <---- $timeout evaluates on nextTick
return defer.promise;
}
}
This is another article that talks about the textTick implementation of $q.
I know that this doesnt solve your problem - but it should shed some light onto why this is happening! Good luck!
1) $timeout needs to be more than 200
First off - I have never seen constructs like $timeout(deferred.reject); I don't believe defered.reject returns any function that $timeout expects.
I tried 50 and it works.
Here is http://plnkr.co/edit/6NXZEXrfz3WHVqoaRYJB?p=preview
with timeout 50 or less but works i.e. All Good! is printed.
resolve: {
test: function($q, $timeout) {
var defer = $q.defer();
$timeout(function(){
defer.reject();
},50);
return defer.promise;
}
}
This is with stateChangeError outside the iconicPlatform.ready
2) $stateChangeError not working
I am thinking that this has to do with the timings. I don;t know the internals as to when the ionicPlatform.ready() gets executed but I am not sure if it is even necessary. Your starter
module depends on it so it will be loaded. Sometimes seed projects have more than 'seed'.
UPDATED - Found a bug with respect to ready() on other devices. It seems that ready method is not getting executed.
https://github.com/driftyco/ionic/issues/1751