Skip to content

Commit 7d1ca54

Browse files
fix(resolve): Add onFinish hook to resolve any dynamicly added resolvables
Closes angular-ui/ui-router#3544
1 parent 3f5d3bb commit 7d1ca54

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

src/hooks/resolve.ts

+24-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import { TransitionService } from '../transition/transitionService';
88
import { val } from '../common/hof';
99
import { StateDeclaration } from '../state/interface';
1010

11+
export const RESOLVE_HOOK_PRIORITY = 1000;
12+
1113
/**
1214
* A [[TransitionHookFn]] which resolves all EAGER Resolvables in the To Path
1315
*
14-
* Registered using `transitionService.onStart({}, eagerResolvePath);`
16+
* Registered using `transitionService.onStart({}, eagerResolvePath, { priority: 1000 });`
1517
*
1618
* When a Transition starts, this hook resolves all the EAGER Resolvables, which the transition then waits for.
1719
*
@@ -23,12 +25,12 @@ const eagerResolvePath: TransitionHookFn = (trans: Transition) =>
2325
.then(noop);
2426

2527
export const registerEagerResolvePath = (transitionService: TransitionService) =>
26-
transitionService.onStart({}, eagerResolvePath, {priority: 1000});
28+
transitionService.onStart({}, eagerResolvePath, {priority: RESOLVE_HOOK_PRIORITY});
2729

2830
/**
2931
* A [[TransitionHookFn]] which resolves all LAZY Resolvables for the state (and all its ancestors) in the To Path
3032
*
31-
* Registered using `transitionService.onEnter({ entering: () => true }, lazyResolveState);`
33+
* Registered using `transitionService.onEnter({ entering: () => true }, lazyResolveState, { priority: 1000 });`
3234
*
3335
* When a State is being entered, this hook resolves all the Resolvables for this state, which the transition then waits for.
3436
*
@@ -41,5 +43,23 @@ const lazyResolveState: TransitionStateHookFn = (trans: Transition, state: State
4143
.then(noop);
4244

4345
export const registerLazyResolveState = (transitionService: TransitionService) =>
44-
transitionService.onEnter({ entering: val(true) }, lazyResolveState, {priority: 1000});
46+
transitionService.onEnter({ entering: val(true) }, lazyResolveState, {priority: RESOLVE_HOOK_PRIORITY});
47+
48+
49+
/**
50+
* A [[TransitionHookFn]] which resolves any dynamically added (LAZY or EAGER) Resolvables.
51+
*
52+
* Registered using `transitionService.onFinish({}, eagerResolvePath, { priority: 1000 });`
53+
*
54+
* After all entering states have been entered, this hook resolves any remaining Resolvables.
55+
* These are typically dynamic resolves which were added by some Transition Hook using [[Transition.addResolvable]].
56+
*
57+
* See [[StateDeclaration.resolve]]
58+
*/
59+
const resolveRemaining: TransitionHookFn = (trans: Transition) =>
60+
new ResolveContext(trans.treeChanges().to)
61+
.resolvePath("LAZY", trans)
62+
.then(noop);
4563

64+
export const registerResolveRemaining = (transitionService: TransitionService) =>
65+
transitionService.onFinish({}, resolveRemaining, {priority: RESOLVE_HOOK_PRIORITY});

src/transition/transitionService.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { UIRouter } from "../router";
1616
import { registerAddCoreResolvables } from "../hooks/coreResolvables";
1717
import { registerRedirectToHook } from "../hooks/redirectTo";
1818
import { registerOnExitHook, registerOnRetainHook, registerOnEnterHook } from "../hooks/onEnterExitRetain";
19-
import { registerEagerResolvePath, registerLazyResolveState } from "../hooks/resolve";
19+
import { registerEagerResolvePath, registerLazyResolveState, registerResolveRemaining } from "../hooks/resolve";
2020
import { registerLoadEnteringViews, registerActivateViews } from "../hooks/views";
2121
import { registerUpdateGlobalState } from "../hooks/updateGlobals";
2222
import { registerUpdateUrl } from "../hooks/url";
@@ -180,6 +180,7 @@ export class TransitionService implements IHookRegistry, Disposable {
180180
onEnter: Function;
181181
eagerResolve: Function;
182182
lazyResolve: Function;
183+
resolveAll: Function;
183184
loadViews: Function;
184185
activateViews: Function;
185186
updateGlobals: Function;
@@ -328,7 +329,7 @@ export class TransitionService implements IHookRegistry, Disposable {
328329

329330
// Wire up redirectTo hook
330331
fns.redirectTo = registerRedirectToHook(this);
331-
332+
332333
// Wire up onExit/Retain/Enter state hooks
333334
fns.onExit = registerOnExitHook(this);
334335
fns.onRetain = registerOnRetainHook(this);
@@ -337,7 +338,8 @@ export class TransitionService implements IHookRegistry, Disposable {
337338
// Wire up Resolve hooks
338339
fns.eagerResolve = registerEagerResolvePath(this);
339340
fns.lazyResolve = registerLazyResolveState(this);
340-
341+
fns.resolveAll = registerResolveRemaining(this);
342+
341343
// Wire up the View management hooks
342344
fns.loadViews = registerLoadEnteringViews(this);
343345
fns.activateViews = registerActivateViews(this);

test/transitionSpec.ts

+33-1
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ describe('transition', function () {
657657
.then(done, done);
658658
}));
659659

660-
it("hooks can add resolves to a $transition$ and they will be available to be injected elsewhere", ((done) => {
660+
it("hooks can add resolves to a $transition$ and they will be available to be injected in nested states", ((done) => {
661661
let log = [], transition = makeTransition("A", "D");
662662
let $q = services.$q;
663663
let defer = $q.defer();
@@ -687,6 +687,38 @@ describe('transition', function () {
687687
.then(done, done);
688688
}));
689689

690+
// test for https://github.com/angular-ui/ui-router/issues/3544
691+
it("hooks can add resolves to a $transition$ and they will be available in onSuccess", ((done) => {
692+
let log = [], transition = makeTransition("A", "B");
693+
let $q = services.$q;
694+
let defer = $q.defer();
695+
696+
$transitions.onEnter({ entering: '**'}, function logEnter(trans, state) {
697+
log.push("Entered#" + state.name);
698+
}, { priority: -1 });
699+
700+
$transitions.onEnter({ entering: "B" }, function addResolves($transition$: Transition) {
701+
log.push("adding resolve");
702+
let resolveFn = function () { log.push("resolving"); return defer.promise; };
703+
$transition$.addResolvable(new Resolvable('newResolve', resolveFn));
704+
});
705+
706+
$transitions.onSuccess({}, function useTheNewResolve(trans) {
707+
log.push('SUCCESS!');
708+
log.push(trans.injector().get('newResolve'));
709+
});
710+
711+
transition.promise.then(function() { log.push("DONE!"); });
712+
713+
transition.run();
714+
715+
tick().then(() => expect(log.join(';')).toBe("adding resolve;Entered#B;resolving"))
716+
.then(() => defer.resolve("resolvedval"))
717+
.then(tick, tick)
718+
.then(() => expect(log.join(';')).toBe("adding resolve;Entered#B;resolving;SUCCESS!;resolvedval;DONE!"))
719+
.then(done, done);
720+
}));
721+
690722
// Test for https://github.com/ui-router/core/issues/32
691723
it('should match "" (empty string) to root state only', async (done) => {
692724
const beforeLog = [], successLog = [];

0 commit comments

Comments
 (0)