Skip to content

Commit 0896646

Browse files
BC-BREAK: Removed Transition.resolves() in favor of Transition.getResolveTokens() and Transition.getResolveValue()
This change is necessary to support injection tokens of arbitrary types, not just strings.
1 parent 5c083bd commit 0896646

File tree

4 files changed

+80
-11
lines changed

4 files changed

+80
-11
lines changed

src/common/common.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export const inherit = (parent, extra) =>
119119
const restArgs = (args, idx = 0) => Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(args, idx));
120120

121121
/** Given an array, returns true if the object is found in the array, (using indexOf) */
122-
const inArray = (array: any[], obj: any) => array.indexOf(obj) !== -1;
122+
export const inArray = (array: any[], obj: any) => array.indexOf(obj) !== -1;
123123

124124
/** Given an array, and an item, if the item is found in the array, it removes it (in-place). The same array is returned */
125125
export const removeFrom = curry((array: any[], obj) => {
@@ -368,7 +368,10 @@ export const unnestR = (memo: any[], elem) => memo.concat(elem);
368368
*/
369369
export const flattenR = (memo: any[], elem) => isArray(elem) ? memo.concat(elem.reduce(flattenR, [])) : pushR(memo, elem);
370370
/** Reduce function that pushes an object to an array, then returns the array. Mostly just for [[flattenR]] */
371-
function pushR(arr: any[], obj) { arr.push(obj); return arr; }
371+
export function pushR(arr: any[], obj) { arr.push(obj); return arr; }
372+
373+
/** Reduce function that filters out duplicates */
374+
export const uniqR = (acc, token) => inArray(acc, token) ? acc : pushR(acc, token);
372375

373376
/**
374377
* Return a new array with a single level of arrays unnested.

src/ng1/statebuilders/onEnterExitRetain.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {TransitionStateHookFn, HookResult} from "../../transition/interface";
44
import {Transition} from "../../transition/transition";
55
import IInjectorService = angular.auto.IInjectorService;
66
import {services} from "../../common/coreservices";
7+
import {isString} from "../../common/predicates";
8+
import {applyPairs} from "../../common/common";
79

810
/**
911
* This is a [[StateBuilder.builder]] function for angular1 `onEnter`, `onExit`,
@@ -16,7 +18,11 @@ export const getStateHookBuilder = (hookName) =>
1618
function stateHookBuilder(state: State, parentFn): TransitionStateHookFn {
1719
let hook = state[hookName];
1820
function decoratedNg1Hook(trans: Transition, inj: IInjectorService): HookResult {
19-
return services.$injector.invoke(hook, this, trans.resolves());
21+
let tokens = trans.getResolveTokens().filter(isString);
22+
let tuples = tokens.map(key => [ key, trans.getResolveValue(key) ]);
23+
let locals = tuples.reduce(applyPairs, {});
24+
25+
return services.$injector.invoke(hook, this, locals);
2026
}
2127

2228
return hook ? decoratedNg1Hook : undefined;

src/resolve/resolveContext.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/** @module resolve */ /** for typedoc */
2-
import {IInjectable, find, filter, map, tail, defaults, extend, pick, omit} from "../common/common";
2+
import {
3+
IInjectable, find, filter, map, tail, defaults, extend, pick, uniqR, unnestR
4+
} from "../common/common";
35
import {prop, propEq} from "../common/hof";
46
import {isString, isObject} from "../common/predicates";
57
import {trace} from "../common/trace";
@@ -74,6 +76,25 @@ export class ResolveContext {
7476
}, <Resolvables> {});
7577
}
7678

79+
/** Gets all the tokens found in the resolve context, de-duplicated */
80+
getTokens() {
81+
return this._path.reduce((acc, node) => acc.concat(node.resolvables.map(r => r.token)), []).reduce(uniqR, []);
82+
}
83+
84+
/**
85+
* Gets the Resolvable that matches the token
86+
*
87+
* Gets the last Resolvable that matches the token in this context, or undefined.
88+
* Throws an error if it doesn't exist in the ResolveContext
89+
*/
90+
getResolvable(token) {
91+
var matching = this._path.map(node => node.resolvables)
92+
.reduce(unnestR, [])
93+
.filter((r: Resolvable) => r.token === token);
94+
95+
return tail(matching)
96+
}
97+
7798
/** Inspects a function `fn` for its dependencies. Returns an object containing any matching Resolvables */
7899
getResolvablesForFn(fn: IInjectable): { [key: string]: Resolvable } {
79100
let deps = services.$injector.annotate(<Function> fn, services.$injector.strictDi);

src/transition/transition.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
map, find, extend, mergeR, tail,
66
omit, toJson, abstractKey, arrayTuples, unnestR, identity, anyTrueR
77
} from "../common/common";
8-
import { isObject } from "../common/predicates";
8+
import { isObject, isArray } from "../common/predicates";
99
import { prop, propEq, val, not } from "../common/hof";
1010

1111
import {StateDeclaration, StateOrName} from "../state/interface";
@@ -214,17 +214,56 @@ export class Transition implements IHookRegistry {
214214
}
215215

216216
/**
217-
* Get resolved data
217+
* Gets all available resolve tokens (keys)
218218
*
219-
* @returns an object (key/value pairs) where keys are resolve names and values are any settled resolve data,
220-
* or `undefined` for pending resolve data
219+
* This method can be used in conjunction with [[getResolve]] to inspect the resolve values
220+
* available to the Transition.
221+
*
222+
* The returned tokens include those defined on [[StateDeclaration.resolve]] blocks, for the states
223+
* in the Transition's [[TreeChanges.to]] path.
224+
*
225+
* @returns an array of resolve tokens (keys)
226+
*/
227+
getResolveTokens(): any[] {
228+
return tail(this._treeChanges.to).resolveContext.getTokens();
229+
}
230+
231+
232+
/**
233+
* Gets resolved values
234+
*
235+
* This method can be used in conjunction with [[getResolveTokens]] to inspect what resolve values
236+
* are available to the Transition.
237+
*
238+
* Given a token, returns the resolved data for that token.
239+
* Given an array of tokens, returns an array of resolved data for those tokens.
240+
*
241+
* If a resolvable hasn't yet been fetched, returns `undefined` for that token
242+
* If a resolvable doesn't exist for the token, throws an error.
243+
*
244+
* @param token the token (or array of tokens)
245+
*
246+
* @returns an array of resolve tokens (keys)
221247
*/
222-
resolves(): { [resolveName: string]: any } {
223-
return map(tail(this._treeChanges.to).resolveContext.getResolvables(), res => res.data);
248+
getResolveValue(token: (any|any[])): (any|any[]) {
249+
var resolveContext = tail(this._treeChanges.to).resolveContext;
250+
const getData = token => {
251+
var resolvable = resolveContext.getResolvable(token);
252+
if (resolvable === undefined) {
253+
throw new Error("Dependency Injection token not found: ${stringify(token)}");
254+
}
255+
return resolvable.data;
256+
};
257+
258+
if (isArray(token)) {
259+
return token.map(getData);
260+
}
261+
262+
return getData(token);
224263
}
225264

226265
/**
227-
* Adds a new [[Resolvable]] (`resolve`) to this transition.
266+
* Dynamically adds a new [[Resolvable]] (`resolve`) to this transition.
228267
*
229268
* @param resolvable an [[Resolvable]] object
230269
* @param state the state in the "to path" which should receive the new resolve (otherwise, the root state)

0 commit comments

Comments
 (0)