Skip to content

Commit

Permalink
fix(lazyLoad): Use UrlService.match() to retry url sync after success…
Browse files Browse the repository at this point in the history
…ful lazy load triggered by url

Closes #19
  • Loading branch information
christopherthielen committed Jan 4, 2017
1 parent 32e64f0 commit 8c2461d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 25 deletions.
47 changes: 22 additions & 25 deletions src/hooks/lazyLoad.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {TransitionHookFn} from "../transition/interface";
import {StateDeclaration, LazyLoadResult} from "../state/interface";
import {State} from "../state/stateObject";
import {services} from "../common/coreservices";
import { StateRule } from "../url/interface";

/**
* A [[TransitionHookFn]] that performs lazy loading
Expand Down Expand Up @@ -33,36 +34,32 @@ import {services} from "../common/coreservices";
const lazyLoadHook: TransitionHookFn = (transition: Transition) => {
const transitionSource = (trans: Transition) =>
trans.redirectedFrom() ? transitionSource(trans.redirectedFrom()) : trans.options().source;
let router = transition.router;

function retryOriginalTransition() {
if (transitionSource(transition) === 'url') {
let $loc = transition.router.urlService,
$reg = transition.router.stateRegistry,
path = $loc.path(),
search = $loc.search(),
hash = $loc.hash();

let matchState = state =>
[state, state.url && state.url.exec(path, search, hash)];

let matches = $reg.get()
.map(s => s.$$state())
.map(matchState)
.filter(([state, params]) => !!params);

if (matches.length) {
let [state, params] = matches[0];
return transition.router.stateService.target(state, params, transition.options());
}
if (transitionSource(transition) !== 'url') {
// The original transition was not triggered via url sync
// The lazy state should be loaded now, so re-try the original transition
let orig = transition.targetState();
return router.stateService.target(orig.identifier(), orig.params(), orig.options());
}

transition.router.urlRouter.sync();
return;
// The original transition was triggered via url sync
// Run the URL rules and find the best match
let $url = router.urlService;
let result = $url.match($url.parts());
let rule = result && result.rule;

// If the best match is a state, redirect the transition (instead
// of calling sync() which supersedes the current transition)
if (rule && rule.type === "STATE") {
let state = (rule as StateRule).state;
let params = result.match;
return router.stateService.target(state, params, transition.options());
}

// The original transition was not triggered via url sync
// The lazy state should be loaded now, so re-try the original transition
let orig = transition.targetState();
return transition.router.stateService.target(orig.identifier(), orig.params(), orig.options());
// No matching state found, so let .sync() choose the best non-state match/otherwise
router.urlRouter.sync();
}

let promises = transition.entering()
Expand Down
23 changes: 23 additions & 0 deletions test/urlRouterSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,29 @@ describe("UrlRouter", function () {
expect(match.rule).toBe(CCC);
});
});

describe('lazy loaded state url', () => {
it("should obey rule priority ordering", (done) => {
let registry = router.stateRegistry;
let loadedState;
const lazyLoad = () => {
loadedState = registry.register({ name: 'lazy', url: '/lazy' });
return null;
};

registry.register({ name: 'lazy.**', url: '/lazy', lazyLoad: lazyLoad });
registry.register({ name: 'param', url: '/:param', });

router.transitionService.onSuccess({}, trans => {
expect(trans.$to()).toBe(loadedState);
expect(trans.redirectedFrom().to().name).toBe('lazy.**');

done();
});

router.urlService.url('/lazy');
})
})
});

describe('UrlRouter.deferIntercept', () => {
Expand Down

0 comments on commit 8c2461d

Please sign in to comment.