Skip to content

Commit

Permalink
fix(resolve): Add onFinish hook to resolve any dynamicly added resolv…
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherthielen committed Dec 22, 2017
1 parent 3f5d3bb commit 7d1ca54
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
28 changes: 24 additions & 4 deletions src/hooks/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { TransitionService } from '../transition/transitionService';
import { val } from '../common/hof';
import { StateDeclaration } from '../state/interface';

export const RESOLVE_HOOK_PRIORITY = 1000;

/**
* A [[TransitionHookFn]] which resolves all EAGER Resolvables in the To Path
*
* Registered using `transitionService.onStart({}, eagerResolvePath);`
* Registered using `transitionService.onStart({}, eagerResolvePath, { priority: 1000 });`
*
* When a Transition starts, this hook resolves all the EAGER Resolvables, which the transition then waits for.
*
Expand All @@ -23,12 +25,12 @@ const eagerResolvePath: TransitionHookFn = (trans: Transition) =>
.then(noop);

export const registerEagerResolvePath = (transitionService: TransitionService) =>
transitionService.onStart({}, eagerResolvePath, {priority: 1000});
transitionService.onStart({}, eagerResolvePath, {priority: RESOLVE_HOOK_PRIORITY});

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

export const registerLazyResolveState = (transitionService: TransitionService) =>
transitionService.onEnter({ entering: val(true) }, lazyResolveState, {priority: 1000});
transitionService.onEnter({ entering: val(true) }, lazyResolveState, {priority: RESOLVE_HOOK_PRIORITY});


/**
* A [[TransitionHookFn]] which resolves any dynamically added (LAZY or EAGER) Resolvables.
*
* Registered using `transitionService.onFinish({}, eagerResolvePath, { priority: 1000 });`
*
* After all entering states have been entered, this hook resolves any remaining Resolvables.
* These are typically dynamic resolves which were added by some Transition Hook using [[Transition.addResolvable]].
*
* See [[StateDeclaration.resolve]]
*/
const resolveRemaining: TransitionHookFn = (trans: Transition) =>
new ResolveContext(trans.treeChanges().to)
.resolvePath("LAZY", trans)
.then(noop);

export const registerResolveRemaining = (transitionService: TransitionService) =>
transitionService.onFinish({}, resolveRemaining, {priority: RESOLVE_HOOK_PRIORITY});
8 changes: 5 additions & 3 deletions src/transition/transitionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { UIRouter } from "../router";
import { registerAddCoreResolvables } from "../hooks/coreResolvables";
import { registerRedirectToHook } from "../hooks/redirectTo";
import { registerOnExitHook, registerOnRetainHook, registerOnEnterHook } from "../hooks/onEnterExitRetain";
import { registerEagerResolvePath, registerLazyResolveState } from "../hooks/resolve";
import { registerEagerResolvePath, registerLazyResolveState, registerResolveRemaining } from "../hooks/resolve";
import { registerLoadEnteringViews, registerActivateViews } from "../hooks/views";
import { registerUpdateGlobalState } from "../hooks/updateGlobals";
import { registerUpdateUrl } from "../hooks/url";
Expand Down Expand Up @@ -180,6 +180,7 @@ export class TransitionService implements IHookRegistry, Disposable {
onEnter: Function;
eagerResolve: Function;
lazyResolve: Function;
resolveAll: Function;
loadViews: Function;
activateViews: Function;
updateGlobals: Function;
Expand Down Expand Up @@ -328,7 +329,7 @@ export class TransitionService implements IHookRegistry, Disposable {

// Wire up redirectTo hook
fns.redirectTo = registerRedirectToHook(this);

// Wire up onExit/Retain/Enter state hooks
fns.onExit = registerOnExitHook(this);
fns.onRetain = registerOnRetainHook(this);
Expand All @@ -337,7 +338,8 @@ export class TransitionService implements IHookRegistry, Disposable {
// Wire up Resolve hooks
fns.eagerResolve = registerEagerResolvePath(this);
fns.lazyResolve = registerLazyResolveState(this);

fns.resolveAll = registerResolveRemaining(this);

// Wire up the View management hooks
fns.loadViews = registerLoadEnteringViews(this);
fns.activateViews = registerActivateViews(this);
Expand Down
34 changes: 33 additions & 1 deletion test/transitionSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ describe('transition', function () {
.then(done, done);
}));

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

// test for https://github.com/angular-ui/ui-router/issues/3544
it("hooks can add resolves to a $transition$ and they will be available in onSuccess", ((done) => {
let log = [], transition = makeTransition("A", "B");
let $q = services.$q;
let defer = $q.defer();

$transitions.onEnter({ entering: '**'}, function logEnter(trans, state) {
log.push("Entered#" + state.name);
}, { priority: -1 });

$transitions.onEnter({ entering: "B" }, function addResolves($transition$: Transition) {
log.push("adding resolve");
let resolveFn = function () { log.push("resolving"); return defer.promise; };
$transition$.addResolvable(new Resolvable('newResolve', resolveFn));
});

$transitions.onSuccess({}, function useTheNewResolve(trans) {
log.push('SUCCESS!');
log.push(trans.injector().get('newResolve'));
});

transition.promise.then(function() { log.push("DONE!"); });

transition.run();

tick().then(() => expect(log.join(';')).toBe("adding resolve;Entered#B;resolving"))
.then(() => defer.resolve("resolvedval"))
.then(tick, tick)
.then(() => expect(log.join(';')).toBe("adding resolve;Entered#B;resolving;SUCCESS!;resolvedval;DONE!"))
.then(done, done);
}));

// Test for https://github.com/ui-router/core/issues/32
it('should match "" (empty string) to root state only', async (done) => {
const beforeLog = [], successLog = [];
Expand Down

0 comments on commit 7d1ca54

Please sign in to comment.