-
-
Save deanapeterson/b93b48fd8c258861f26b to your computer and use it in GitHub Desktop.
(function(){ | |
"use strict"; | |
/** | |
* Hijacks the ui-router $state.transitionTo() method to capture it's promise. | |
* the promise is added to the $state as $promise (may or may not be needed); | |
* also adds handler for rejection of the $promise. | |
*/ | |
angular | |
.module("stm.ui.stateChangeRejected", ['ui.router']) | |
.config(stateChangeRejected); | |
function stateChangeRejected($provide){ | |
$provide.decorator("$state", decorateTransitionTo); | |
decorateTransitionTo.$inject = ['$delegate', '$rootScope']; | |
function decorateTransitionTo($delegate, $rootScope){ //$delegate === $state | |
var nativeTransitionTo = $delegate.transitionTo; //transfer reference | |
$delegate.transitionTo = transitionToWrapper;// replace with wrapper | |
return $delegate; | |
function transitionToWrapper(){ | |
var args = [].slice.call(arguments); | |
var promise = nativeTransitionTo.apply(this, args);//call original transitionTo, capture promise | |
promise['catch'](onStateRejection); //add handler for rejection | |
$delegate.$promise = promise; //add $promise to default $state object | |
return promise; | |
function onStateRejection(error){ | |
var toState = $delegate.get(args[0]); | |
var toParams = args[1]; | |
$rootScope.$broadcast("$stateChangeRejected", toState, toParams, $delegate.current, $delegate.params, error); | |
return error; | |
} | |
} | |
} | |
} | |
}()); |
I think that for a lot of reasons it will be better to return the promise generated by this guy:
promise['catch'](onStateRejection);
Also you can throw / return rejection with the error after the broadcast (from onStateRejection).
** Just an idea:
var promise = nativeTransitionTo.apply(this, args);//call original transitionTo, capture promise
promise = promise['catch'](onStateRejection); //add handler for rejection
$delegate.$promise = promise; //add $promise to default $state object
return promise;
function onStateRejection(error){
var toState = $delegate.get(args[0]);
var toParams = args[1];
$rootScope.$broadcast("$stateChangeRejected", toState, toParams, $delegate.current, $delegate.params, error);
return $q.reject(error);
}
@sabrehagen, rejections are when a event.preventDefault() is executed inside the "$stateChangeStart/Success" handlers. Also if a dependency doesn't resolve and returns a rejected promise which is changed to transitionTo promise.
@bogdanalexe90, UPDATED, thanks for reminding me. Pretty sure I don't need to use $q.reject as returned value is converted into a rejected promise automatically. Thanks
If you use return then you will recover from error and you will end up in success callback for the promise returned by the .then() method. You must use $q.reject() (or throw an error) in order to reject the returned promise. This explains better (look at the example) https://docs.angularjs.org/api/ng/service/$q#reject
Also you must return the promise generated from here:
promise['catch'](onStateRejection);
- In order to be sure that this will happen sequentially (first the broadcast and then the final handle of the promise).
@bogdanalexe90, I'm gonna take a look at that. Thanks
Thank you @deanapeterson ! It's an informative gist that works on v0.2.18 :)
how does onStateRejection get thrown? is this the responsibility of the user?