Skip to content

Commit 221103e

Browse files
refactor(TransitionHooks): Use TransitionService for built-in hooks, not Transition instance hooks
1 parent d2e28cf commit 221103e

20 files changed

+233
-256
lines changed

src/hooks/onEnterExitRetain.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/** @module state */ /** for typedoc */
2+
import {TransitionStateHookFn} from "../transition/interface";
3+
import {UIRInjector} from "../common/interface";
4+
import {State} from "../state/stateObject";
5+
import {Transition} from "../transition/transition";
6+
7+
export function makeEnterExitRetainHook(hookName: string): TransitionStateHookFn {
8+
return (transition: Transition, injector: UIRInjector, state: State) =>
9+
state[hookName](transition, injector, state);
10+
}

src/hooks/redirectTo.ts

Whitespace-only changes.

src/hooks/resolve.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/** @module state */ /** for typedoc */
2+
import {noop} from "../common/common";
3+
import {Transition} from "../transition/transition";
4+
import {State} from "../state/stateObject";
5+
import {ResolveContext} from "../resolve/resolveContext";
6+
7+
/** A function which resolves all EAGER Resolvables in the To Path */
8+
export const $eagerResolvePath = (trans: Transition) =>
9+
new ResolveContext(trans.treeChanges().to).resolvePath("EAGER", trans).then(noop);
10+
11+
/** A function which resolves all LAZY Resolvables for the state (and all ancestors) in the To Path */
12+
export const $lazyResolveState = (trans: Transition, injector, state: State) =>
13+
new ResolveContext(trans.treeChanges().to).subContext(state).resolvePath("LAZY", trans).then(noop);
14+

src/hooks/transitionManager.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/** @module state */ /** for typedoc */
2+
import {Transition} from "../transition/transition";
3+
import {Rejection, RejectType} from "../transition/rejectFactory";
4+
5+
import {StateDeclaration} from "../state/interface";
6+
import {StateService} from "../state/stateService";
7+
import {TargetState} from "../state/targetState";
8+
import {UrlRouter} from "../url/urlRouter";
9+
import {services} from "../common/coreservices";
10+
import {Globals} from "../globals";
11+
import {ViewService} from "../view/view";
12+
import {TransitionService} from "../transition/transitionService";
13+
14+
/**
15+
* Adds the built-in UI-Router hooks to a [[Transition]]
16+
*
17+
* * Takes a blank transition object and adds all the hooks necessary for it to behave like a state transition.
18+
*
19+
* * Runs the transition, returning a chained promise which:
20+
* * transforms the resolved Transition.promise to the final destination state.
21+
* * manages the rejected Transition.promise, checking for Dynamic or Redirected transitions
22+
*
23+
* * Registers a handler to update global $state data such as "active transitions" and "current state/params"
24+
*
25+
* * Registers view hooks, which maintain the list of active view configs and sync with/update the ui-views
26+
*
27+
* * Registers onEnter/onRetain/onExit hooks which delegate to the state's hooks of the same name, at the appropriate time
28+
*
29+
* * Registers eager and lazy resolve hooks
30+
*/
31+
export class TransitionManager {
32+
private $q;
33+
private getRedirectedMgr: (redirect: Transition) => TransitionManager;
34+
35+
constructor(
36+
private transition: Transition,
37+
private $transitions: TransitionService,
38+
private $urlRouter: UrlRouter,
39+
$view: ViewService,
40+
private $state: StateService,
41+
private globals: Globals
42+
) {
43+
this.$q = services.$q;
44+
this.getRedirectedMgr = (redirect: Transition) =>
45+
new TransitionManager(redirect, $transitions, $urlRouter, $view, $state, globals);
46+
}
47+
48+
runTransition(): Promise<any> {
49+
this.globals.transitionHistory.enqueue(this.transition);
50+
return this.transition.run()
51+
.then((trans: Transition) => trans.to()) // resolve to the final state (TODO: good? bad?)
52+
.catch(error => this.transRejected(error)); // if rejected, handle dynamic and redirect
53+
}
54+
55+
transRejected(error): (StateDeclaration|Promise<any>) {
56+
// Handle redirect and abort
57+
if (error instanceof Rejection) {
58+
if (error.type === RejectType.IGNORED) {
59+
this.$urlRouter.update();
60+
return this.$state.current;
61+
}
62+
63+
if (error.type === RejectType.SUPERSEDED && error.redirected && error.detail instanceof TargetState) {
64+
return this.getRedirectedMgr(this.transition.redirect(error.detail)).runTransition();
65+
}
66+
67+
if (error.type === RejectType.ABORTED) {
68+
this.$urlRouter.update();
69+
}
70+
}
71+
72+
this.$transitions.defaultErrorHandler()(error);
73+
74+
return this.$q.reject(error);
75+
}
76+
}

src/hooks/url.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {UrlRouter} from "../url/urlRouter";
2+
import {StateService} from "../state/stateService";
3+
import {Transition} from "../transition/transition";
4+
import {UIRInjector} from "../common/interface";
5+
import {UiRouter} from "../router";
6+
7+
export function updateUrl(transition: Transition, injector: UIRInjector) {
8+
let options = transition.options();
9+
var router: UiRouter = injector.get(UiRouter);
10+
let $state: StateService = router.stateService;
11+
let $urlRouter: UrlRouter = router.urlRouter;
12+
13+
if (options.location && $state.$current.navigable) {
14+
var urlOptions = {replace: options.location === 'replace'};
15+
$urlRouter.push($state.$current.navigable.url, $state.params, urlOptions);
16+
}
17+
18+
$urlRouter.update(true);
19+
}

src/hooks/views.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/** @module state */ /** for typedoc */
2+
import {noop} from "../common/common";
3+
import {services} from "../common/coreservices";
4+
import {Transition} from "../transition/transition";
5+
import {ViewService} from "../view/view";
6+
import {ViewConfig} from "../view/interface";
7+
import {TransitionService} from "../transition/transitionService";
8+
import {UIRInjector} from "../common/interface";
9+
import {UiRouter} from "../router";
10+
11+
12+
/** Allows the views to do async work [.load()] before the transition continues */
13+
export function loadEnteringViews(transition) {
14+
let enteringViews = transition.views("entering");
15+
if (!enteringViews.length) return;
16+
return services.$q.all(enteringViews.map(view => view.load())).then(noop);
17+
}
18+
19+
export function activateViews(transition: Transition, injector: UIRInjector) {
20+
let enteringViews = transition.views("entering");
21+
let exitingViews = transition.views("exiting");
22+
if (!enteringViews.length && !exitingViews.length) return;
23+
24+
let $view: ViewService = injector.get(UiRouter).viewService;
25+
26+
exitingViews.forEach((vc: ViewConfig) => $view.deactivateViewConfig(vc));
27+
enteringViews.forEach((vc: ViewConfig) => $view.activateViewConfig(vc));
28+
29+
$view.sync();
30+
}

src/ng1/statebuilders/onEnterExitRetain.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import IInjectorService = angular.auto.IInjectorService;
66
import {services} from "../../common/coreservices";
77
import {getLocals} from "../services";
88
import {ResolveContext} from "../../resolve/resolveContext";
9+
import {extend} from "../../common/common";
910

1011
/**
1112
* This is a [[StateBuilder.builder]] function for angular1 `onEnter`, `onExit`,
@@ -17,9 +18,9 @@ import {ResolveContext} from "../../resolve/resolveContext";
1718
export const getStateHookBuilder = (hookName) =>
1819
function stateHookBuilder(state: State, parentFn): TransitionStateHookFn {
1920
let hook = state[hookName];
20-
function decoratedNg1Hook(trans: Transition, inj: IInjectorService): HookResult {
21+
function decoratedNg1Hook(trans: Transition, inj: IInjectorService, state): HookResult {
2122
let resolveContext = new ResolveContext(trans.treeChanges().to);
22-
return services.$injector.invoke(hook, this, getLocals(resolveContext));
23+
return services.$injector.invoke(hook, this, extend({ $state$: state }, getLocals(resolveContext)));
2324
}
2425

2526
return hook ? decoratedNg1Hook : undefined;

src/router.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {UiRouterGlobals, Globals} from "./globals";
2121
export class UiRouter {
2222
viewService = new ViewService();
2323

24-
transitionService: TransitionService = new TransitionService(this.viewService);
24+
transitionService: TransitionService = new TransitionService(this);
2525

2626
globals: UiRouterGlobals = new Globals(this.transitionService);
2727

src/state/hooks/enterExitHooks.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/state/hooks/resolveHooks.ts

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)