Skip to content

Commit fc2a888

Browse files
feat(Transition): Create resolves() method on Transition to return resolved data.
feat(Transition): Create addResolve() method on Transition to programmatically add resolves to a transition
1 parent de36f2f commit fc2a888

File tree

5 files changed

+42
-26
lines changed

5 files changed

+42
-26
lines changed

src/resolve/resolvable.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/// <reference path='../../typings/angularjs/angular.d.ts' />
2-
import {pick, map} from "../common/common";
2+
import {pick, map, filter, not, isFunction} from "../common/common";
33
import trace from "../common/trace";
44
import {runtime} from "../common/angular1"
55
import {IPromise} from "angular";
66

7+
import {IResolveDeclarations} from "../state/interface";
78
import {State} from "../state/state";
89

910
import {IResolvables, IOptions1} from "./interface"
@@ -90,4 +91,15 @@ export default class Resolvable {
9091
toString() {
9192
return `Resolvable(name: ${this.name}, state: ${this.state.name}, requires: [${this.deps}])`;
9293
}
94+
95+
/**
96+
* Validates the result map as a "resolve:" style object, then transforms the resolves into Resolvables
97+
*/
98+
static makeResolvables(resolves: IResolveDeclarations): IResolvables {
99+
// If a hook result is an object, it should be a map of strings to functions.
100+
let invalid = filter(resolves, not(isFunction)), keys = Object.keys(invalid);
101+
if (keys.length)
102+
throw new Error(`Invalid resolve key/value: ${keys[0]}/${invalid[keys[0]]}`);
103+
return map(resolves, (fn, name) => new Resolvable(name, fn));
104+
}
93105
}

src/transition/hookBuilder.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,10 @@ export default class HookBuilder {
7777
*/
7878
private _getTransitionHooks(hookType: string, context: (Node[]|State), locals = {}, options: ITransitionHookOptions = {}) {
7979
let node = tail(this.treeChanges.to);
80-
let toFrom: IToFrom = this._toFrom();
8180
options.traceData = { hookType, context };
8281

8382
const transitionHook = eventHook => this.buildHook(node, eventHook.callback, locals, options);
84-
return this._matchingHooks(hookType, toFrom).map(transitionHook);
83+
return this._matchingHooks(hookType, this._toFrom()).map(transitionHook);
8584
}
8685

8786
/**

src/transition/transition.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ import PathFactory from "../path/pathFactory";
1515

1616
import {State} from "../state/state";
1717
import TargetState from "../state/targetState";
18-
import {IStateDeclaration} from "../state/interface";
18+
import {IStateDeclaration, IStateOrName} from "../state/interface";
1919

2020
import Param from "../params/param";
2121

22+
import Resolvable from "../resolve/resolvable";
23+
24+
import {IResolveDeclarations} from "../state/interface";
25+
2226
import {ViewConfig} from "../view/view";
2327

2428
import {
@@ -149,6 +153,23 @@ export class Transition implements IHookRegistry {
149153
return this._treeChanges[pathname].map(prop("values")).reduce(mergeR, {});
150154
}
151155

156+
/**
157+
* Returns an object with any settled resolve data
158+
*/
159+
resolves = () => map(tail(this._treeChanges.to).resolveContext.getResolvables(), res => res.data);
160+
161+
/**
162+
* Adds new resolves to this transition.
163+
* @param resolves a IResolveDeclarations object which describes the new resolves
164+
* @param state (optional) the state in the topath which should receive the new resolves (otherwise, the root state)
165+
*/
166+
addResolves(resolves: IResolveDeclarations, state: IStateOrName = "") {
167+
let stateName = state.name ? state.name : state;
168+
let topath = this._treeChanges.to;
169+
let targetNode = find(topath, node => node.state.name === stateName);
170+
tail(topath).resolveContext.addResolvables(Resolvable.makeResolvables(resolves), targetNode.state);
171+
}
172+
152173
/**
153174
* @ngdoc function
154175
* @name ui.router.state.type:Transition#previous

src/transition/transitionHook.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ export default class TransitionHook {
4343
// If the hook returns a Transition, halt the current Transition and redirect to that Transition.
4444
[is(Transition), (transition) => REJECT.redirected(transition)],
4545
// A promise was returned, wait for the promise and then chain another hookHandler
46-
[isPromise, (promise) => promise.then(this.handleHookResult.bind(this))],
47-
// If the hook returns any new resolves, add them to the pathContext via the PathElement
48-
[isObject, (obj) => this.resolveContext.addResolvables(this.mapNewResolves(obj), this.state)]
46+
[isPromise, (promise) => promise.then(this.handleHookResult.bind(this))]
4947
]);
5048

5149
invokeStep = (moreLocals) => {
@@ -64,20 +62,6 @@ export default class TransitionHook {
6462
return resolveContext.invokeLater(fn, locals, options).then(this.handleHookResult.bind(this));
6563
};
6664

67-
/**
68-
* Validates the result map as a "resolve:" style object.
69-
* Creates Resolvable objects from the result object and adds them to the target object
70-
*/
71-
mapNewResolves(resolves: IResolveDeclarations) {
72-
// If a hook result is an object, it should be a map of strings to functions.
73-
let invalid = filter(resolves, not(isFunction)), keys = Object.keys(invalid);
74-
if (keys.length)
75-
throw new Error(`Invalid resolve key/value: ${keys[0]}/${invalid[keys[0]]}`);
76-
77-
const makeResolvable = (fn, name) => new Resolvable(name, fn);
78-
return map(resolves, makeResolvable);
79-
}
80-
8165
handleHookResult(hookResult) {
8266
if (!isDefined(hookResult)) return undefined;
8367
trace.traceHookResult(hookResult, undefined, this.options);

test/transitionSpec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,17 @@ describe('transition', function () {
394394
resolveDeferredFor("D"); expect(log.join(';')).toBe("#B;^B;#C;^C;#D;^D;DONE");
395395
}));
396396

397-
it("resolve-like objects returned from hooks should be added to the transition as Resolvables", inject(function($transitions, $q, $timeout) {
397+
it("hooks can add resolves to a $transition$ and they will be available to be injected elsewhere", inject(function($transitions, $q, $timeout) {
398398
var log = [], transition = makeTransition("A", "D");
399399
var defer = $q.defer();
400400

401401
transitionProvider.onEnter({}, function logEnter($state$) { log.push("Entered#"+$state$.name); }, {priority: -1});
402402

403-
transitionProvider.onEnter({ to: "B" }, function addResolves() {
403+
transitionProvider.onEnter({ to: "B" }, function addResolves($transition$) {
404404
log.push("adding resolve");
405-
return {
406-
newResolve: function() { log.push("resolving"); return defer.promise; }
407-
}
405+
$transition$.addResolves({
406+
newResolve: function () { log.push("resolving"); return defer.promise; }
407+
})
408408
});
409409

410410
transitionProvider.onEnter({ to: "C" }, function useTheNewResolve(newResolve) {

0 commit comments

Comments
 (0)