1
1
/** @module state */ /** */
2
- import { extend , defaults , silentRejection , silenceUncaughtInPromise } from "../common/common" ;
2
+ import { extend , defaults , silentRejection , silenceUncaughtInPromise , removeFrom } from "../common/common" ;
3
3
import { isDefined , isObject , isString } from "../common/predicates" ;
4
4
import { Queue } from "../common/queue" ;
5
5
import { services } from "../common/coreservices" ;
@@ -25,9 +25,16 @@ import {HrefOptions} from "./interface";
25
25
import { bindFunctions } from "../common/common" ;
26
26
import { Globals } from "../globals" ;
27
27
import { UIRouter } from "../router" ;
28
- import { StateParams } from "../params/stateParams" ; // for params() return type
28
+ import { UIInjector } from "../common/interface" ;
29
+ import { ResolveContext } from "../resolve/resolveContext" ;
30
+ import { StateParams } from "../params/stateParams" ; // has or is using
31
+
32
+ export type OnInvalidCallback =
33
+ ( toState ?: TargetState , fromState ?: TargetState , injector ?: UIInjector ) => HookResult ;
29
34
30
35
export class StateService {
36
+ invalidCallbacks : OnInvalidCallback [ ] = [ ] ;
37
+
31
38
get transition ( ) { return this . router . globals . transition ; }
32
39
get params ( ) { return this . router . globals . params ; }
33
40
get current ( ) { return this . router . globals . current ; }
@@ -49,16 +56,13 @@ export class StateService {
49
56
*
50
57
* If a callback returns an TargetState, then it is used as arguments to $state.transitionTo() and the result returned.
51
58
*/
52
- private _handleInvalidTargetState ( fromPath : PathNode [ ] , $to$ : TargetState ) {
59
+ private _handleInvalidTargetState ( fromPath : PathNode [ ] , toState : TargetState ) {
60
+ let fromState = PathFactory . makeTargetState ( fromPath ) ;
53
61
let globals = < Globals > this . router . globals ;
54
62
const latestThing = ( ) => globals . transitionHistory . peekTail ( ) ;
55
63
let latest = latestThing ( ) ;
56
- let $from$ = PathFactory . makeTargetState ( fromPath ) ;
57
- let callbackQueue = new Queue < Function > ( this . router . stateProvider . invalidCallbacks . slice ( ) ) ;
58
- let { $q, $injector} = services ;
59
-
60
- const invokeCallback = ( callback : Function ) =>
61
- $q . when ( $injector . invoke ( callback , null , { $to$, $from$ } ) ) ;
64
+ let callbackQueue = new Queue < OnInvalidCallback > ( this . invalidCallbacks . slice ( ) ) ;
65
+ let injector = new ResolveContext ( fromPath ) . injector ( ) ;
62
66
63
67
const checkForRedirect = ( result : HookResult ) => {
64
68
if ( ! ( result instanceof TargetState ) ) {
@@ -76,13 +80,47 @@ export class StateService {
76
80
77
81
function invokeNextCallback ( ) {
78
82
let nextCallback = callbackQueue . dequeue ( ) ;
79
- if ( nextCallback === undefined ) return Rejection . invalid ( $to$ . error ( ) ) . toPromise ( ) ;
80
- return invokeCallback ( nextCallback ) . then ( checkForRedirect ) . then ( result => result || invokeNextCallback ( ) ) ;
83
+ if ( nextCallback === undefined ) return Rejection . invalid ( toState . error ( ) ) . toPromise ( ) ;
84
+
85
+ let callbackResult = services . $q . when ( nextCallback ( toState , fromState , injector ) ) ;
86
+ return callbackResult . then ( checkForRedirect ) . then ( result => result || invokeNextCallback ( ) ) ;
81
87
}
82
88
83
89
return invokeNextCallback ( ) ;
84
90
}
85
91
92
+ /**
93
+ * Registers an Invalid State handler
94
+ *
95
+ * Registers a [[OnInvalidCallback]] function to be invoked when [[StateService.transitionTo]]
96
+ * has been called with an invalid state reference parameter
97
+ *
98
+ * Example:
99
+ * ```js
100
+ * stateService.onInvalid(function(to, from, injector) {
101
+ * if (to.name() === 'foo') {
102
+ * let lazyLoader = injector.get('LazyLoadService');
103
+ * return lazyLoader.load('foo')
104
+ * .then(() => stateService.target('foo'));
105
+ * }
106
+ * });
107
+ * ```
108
+ *
109
+ * @param {function } callback invoked when the toState is invalid
110
+ * This function receives the (invalid) toState, the fromState, and an injector.
111
+ * The function may optionally return a [[TargetState]] or a Promise for a TargetState.
112
+ * If one is returned, it is treated as a redirect.
113
+ *
114
+ * @returns a function which deregisters the callback
115
+ */
116
+ onInvalid ( callback : OnInvalidCallback ) : Function {
117
+ this . invalidCallbacks . push ( callback ) ;
118
+ return function deregisterListener ( ) {
119
+ removeFrom ( this . invalidCallbacks ) ( callback ) ;
120
+ } . bind ( this ) ;
121
+ }
122
+
123
+
86
124
/**
87
125
* @ngdoc function
88
126
* @name ui.router.state.$state#reload
0 commit comments