Skip to content

Commit 7c9d1a1

Browse files
BC-BREAK: Removed ResolvePolicy enum in favor of the ResolvePolicy interface { when: "", async: "" }
BC-BREAK: renamed `ResolveContext.isolateRootTo` to `subContext` BC-BREAK: rename `UIRouterGlobals` class to `Globals`; add `UIRouterGlobals` as interface feat(ParamType): allow a parameter type to specify a default val for dynamic feat(Resolvable): RXWAIT: resolve to an Observable, but also wait for the first value to emit refactor(Resolvable): pre-compute the resolve policy in resolvableBuilder chore(trace): Pass transition directly to resolve trace functions
1 parent e712deb commit 7c9d1a1

20 files changed

+430
-244
lines changed

packages/ng2/webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module.exports = {
4949
},
5050

5151
externals: {
52+
"rxjs/Rx": { root: 'rxjs/Rx', amd: 'rxjs/Rx', commonjs2: 'rxjs/Rx', commonjs: 'rxjs/Rx' },
5253
"@angular/core": { root: '@angular/core', amd: '@angular/core', commonjs2: '@angular/core', commonjs: '@angular/core' },
5354
"@angular/common": { root: '@angular/common', amd: '@angular/common', commonjs2: '@angular/common', commonjs: '@angular/common' }
5455
}

src/common/trace.ts

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ import {isNumber} from "../common/predicates";
3434
import {Transition} from "../transition/transition";
3535
import {ActiveUIView, ViewConfig} from "../view/interface";
3636
import {stringify, functionToString, maxLength, padString} from "./strings";
37+
import {Resolvable} from "../resolve/resolvable";
38+
import {PathNode} from "../path/node";
39+
import {PolicyWhen} from "../resolve/interface";
3740

3841
/** @hidden */
3942
function uiViewString (viewData) {
@@ -140,11 +143,11 @@ export class Trace {
140143
}
141144

142145
/** called by ui-router code */
143-
traceTransitionIgnored(transition: Transition) {
146+
traceTransitionIgnored(trans: Transition) {
144147
if (!this.enabled(Category.TRANSITION)) return;
145-
let tid = transition.$id,
148+
let tid = trans && trans.$id,
146149
digest = this.approximateDigests,
147-
transitionStr = stringify(transition);
150+
transitionStr = stringify(trans);
148151
console.log(`Transition #${tid} Digest #${digest}: Ignored <> ${transitionStr}`);
149152
}
150153

@@ -170,72 +173,40 @@ export class Trace {
170173
}
171174

172175
/** called by ui-router code */
173-
traceResolvePath(path, options) {
176+
traceResolvePath(path: PathNode[], when: PolicyWhen, trans?: Transition) {
174177
if (!this.enabled(Category.RESOLVE)) return;
175-
let tid = parse("transition.$id")(options),
178+
let tid = trans && trans.$id,
176179
digest = this.approximateDigests,
177-
pathStr = path && path.toString(),
178-
policyStr = options && options.resolvePolicy;
179-
console.log(`Transition #${tid} Digest #${digest}: Resolving ${pathStr} (${policyStr})`);
180+
pathStr = path && path.toString();
181+
console.log(`Transition #${tid} Digest #${digest}: Resolving ${pathStr} (${when})`);
180182
}
181183

182184
/** called by ui-router code */
183-
traceResolvePathElement(pathElement, resolvablePromises, options) {
185+
traceResolvableResolved(resolvable: Resolvable, trans?: Transition) {
184186
if (!this.enabled(Category.RESOLVE)) return;
185-
if (!resolvablePromises.length) return;
186-
let tid = parse("transition.$id")(options),
187-
digest = this.approximateDigests,
188-
resolvablePromisesStr = Object.keys(resolvablePromises).join(", "),
189-
pathElementStr = pathElement && pathElement.toString(),
190-
policyStr = options && options.resolvePolicy;
191-
console.log(`Transition #${tid} Digest #${digest}: Resolve ${pathElementStr} resolvables: [${resolvablePromisesStr}] (${policyStr})`);
192-
}
193-
194-
/** called by ui-router code */
195-
traceResolveResolvable(resolvable, options) {
196-
if (!this.enabled(Category.RESOLVE)) return;
197-
let tid = parse("transition.$id")(options),
198-
digest = this.approximateDigests,
199-
resolvableStr = resolvable && resolvable.toString();
200-
console.log(`Transition #${tid} Digest #${digest}: Resolving -> ${resolvableStr}`);
201-
}
202-
203-
/** called by ui-router code */
204-
traceResolvableResolved(resolvable, options) {
205-
if (!this.enabled(Category.RESOLVE)) return;
206-
let tid = parse("transition.$id")(options),
187+
let tid = trans && trans.$id,
207188
digest = this.approximateDigests,
208189
resolvableStr = resolvable && resolvable.toString(),
209190
result = stringify(resolvable.data);
210191
console.log(`Transition #${tid} Digest #${digest}: <- Resolved ${resolvableStr} to: ${maxLength(200, result)}`);
211192
}
212193

213194
/** called by ui-router code */
214-
tracePathElementInvoke(node, fn, deps, options) {
215-
if (!this.enabled(Category.INVOKE)) return;
216-
let tid = parse("transition.$id")(options),
217-
digest = this.approximateDigests,
218-
stateName = node && node.state && node.state.toString(),
219-
fnName = functionToString(fn);
220-
console.log(`Transition #${tid} Digest #${digest}: Invoke ${options.when}: context: ${stateName} ${maxLength(200, fnName)}`);
221-
}
222-
223-
/** called by ui-router code */
224-
traceError(error, transition: Transition) {
195+
traceError(error, trans: Transition) {
225196
if (!this.enabled(Category.TRANSITION)) return;
226-
let tid = transition.$id,
197+
let tid = trans && trans.$id,
227198
digest = this.approximateDigests,
228-
transitionStr = stringify(transition);
199+
transitionStr = stringify(trans);
229200
console.log(`Transition #${tid} Digest #${digest}: <- Rejected ${transitionStr}, reason: ${error}`);
230201
}
231202

232203
/** called by ui-router code */
233-
traceSuccess(finalState, transition: Transition) {
204+
traceSuccess(finalState, trans: Transition) {
234205
if (!this.enabled(Category.TRANSITION)) return;
235-
let tid = transition.$id,
206+
let tid = trans && trans.$id,
236207
digest = this.approximateDigests,
237208
state = finalState.name,
238-
transitionStr = stringify(transition);
209+
transitionStr = stringify(trans);
239210
console.log(`Transition #${tid} Digest #${digest}: <- Success ${transitionStr}, final state: ${state}`);
240211
}
241212

src/globals.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,21 @@ import {Transition} from "./transition/transition";
66
import {Queue} from "./common/queue";
77
import {TransitionService} from "./transition/transitionService";
88
import {copy} from "./common/common";
9+
import {Observable} from "rxjs/Rx";
910

1011
/**
1112
* Global mutable state
1213
*
1314
* This is where we hold the global mutable state such as current state, current
14-
* params, current transition, last successful transition, last attempted transition, etc.
15+
* params, current transition, etc.
1516
*/
16-
export class UIRouterGlobals {
17+
export interface UIRouterGlobals {
1718
/**
1819
* Current parameter values
1920
*
2021
* The parameter values from the latest successful transition
2122
*/
22-
params: StateParams = new StateParams();
23+
params: StateParams;
2324
/**
2425
* Current state
2526
*
@@ -36,17 +37,18 @@ export class UIRouterGlobals {
3637
* The current transition (in progress)
3738
*/
3839
transition: Transition;
39-
/**
40-
* The transition history
41-
*
42-
* This queue's size is limited to a maximum number (default: 1)
43-
*/
40+
}
41+
42+
43+
/**
44+
* Global mutable state
45+
*/
46+
export class Globals implements UIRouterGlobals {
47+
params: StateParams = new StateParams();
48+
current: StateDeclaration;
49+
$current: State;
50+
transition: Transition;
4451
transitionHistory = new Queue<Transition>([], 1);
45-
/**
46-
* The history of successful transitions
47-
*
48-
* This queue's size is limited to a maximum number (default: 1)
49-
*/
5052
successfulTransitions = new Queue<Transition>([], 1);
5153

5254
constructor(transitionService: TransitionService) {

src/ng2/directives/uiSrefStatus.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {TargetState} from "../../state/targetState";
99
import {TreeChanges} from "../../transition/interface";
1010
import {State} from "../../state/stateObject";
1111
import {anyTrueR, tail, unnestR} from "../../common/common";
12-
import {UIRouterGlobals} from "../../globals";
12+
import {UIRouterGlobals, Globals} from "../../globals";
1313
import {Param} from "../../params/param";
1414
import {PathFactory} from "../../path/pathFactory";
1515

@@ -53,7 +53,7 @@ export class UiSrefStatus {
5353
};
5454

5555
constructor(transitionService: TransitionService,
56-
private _globals: UIRouterGlobals,
56+
private _globals: Globals,
5757
private _stateService: StateService,
5858
public sref: UiSref) {
5959
this._deregisterHook = transitionService.onStart({}, $transition$ => this.processTransition($transition$));

src/ng2/providers.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ import {UiView} from "./directives/uiView";
5959
import {ng2ViewsBuilder, Ng2ViewConfig} from "./statebuilders/views";
6060
import {Ng2ViewDeclaration} from "./interface";
6161
import {UIRouterConfig} from "./uiRouterConfig";
62-
import {UIRouterGlobals} from "../globals";
62+
import {Globals} from "../globals";
6363
import {UIRouterLocation} from "./location";
6464
import {services} from "../common/coreservices";
65+
import {ProviderLike} from "../state/interface";
6566

6667
let uiRouterFactory = (routerConfig: UIRouterConfig, location: UIRouterLocation, injector: Injector) => {
6768
services.$injector.get = injector.get.bind(injector);
@@ -117,15 +118,7 @@ export const UIROUTER_PROVIDERS: ProviderLike[] = [
117118

118119
{ provide: StateRegistry, useFactory: (r: UIRouter) => { return r.stateRegistry; }, deps: [UIRouter]},
119120

120-
{ provide: UIRouterGlobals, useFactory: (r: UIRouter) => { return r.globals; }, deps: [UIRouter]},
121+
{ provide: Globals, useFactory: (r: UIRouter) => { return r.globals; }, deps: [UIRouter]},
121122

122123
{ provide: UiView.PARENT_INJECT, useFactory: (r: StateRegistry) => { return { fqn: null, context: r.root() } }, deps: [StateRegistry]}
123-
];
124-
125-
export interface ProviderLike {
126-
provide: any,
127-
useClass?: any,
128-
useFactory?: Function,
129-
deps?: any[]
130-
}
131-
124+
];

src/params/interface.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,13 @@ export interface ParamDeclaration {
210210
* This is not part of the declaration; it is a calculated value depending on if a default value was specified or not.
211211
*/
212212
isOptional: boolean;
213-
/** @todo document this one too */
213+
/**
214+
* Dynamic flag
215+
*
216+
* When `dynamic` is `true`, changes to the parameter value will not cause the state to be entered/exited.
217+
*
218+
* The resolves will not be re-fetched, nor will views be recreated.
219+
*/
214220
dynamic: boolean;
215221
}
216222

src/params/type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ function ArrayType(type, mode) {
4646
});
4747

4848
extend(this, {
49+
dynamic: type.dynamic,
4950
name: type.name,
5051
pattern: type.pattern,
5152
is: arrayHandler(type.is.bind(type), true),

src/resolve/interface.ts

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,107 @@ export interface Resolvables {
55
[key: string]: Resolvable;
66
}
77

8-
export interface IOptions1 {
9-
omitOwnLocals ?: string[];
10-
resolvePolicy ?: string;
8+
/**
9+
* A plain object used to describe a [[Resolvable]]
10+
*
11+
* These objects may be defined in [[StateDefinition.resolve]] blocks to declare
12+
* async data that the state or substates require.
13+
*/
14+
export interface ResolvableLiteral {
15+
/** The Dependency Injection token that will be used to inject/access the resolvable */
16+
token: any;
17+
18+
/**
19+
* The function that returns one of:
20+
*
21+
* - The resolved value (synchronously)
22+
* - A promise for the resolved value
23+
* - An Observable of the resolved value(s)
24+
*
25+
* This function will be provided the dependencies listed in [[deps]] as its arguments.
26+
* The resolve system will asynchronously fetch the dependencies before invoking this function.
27+
*/
28+
resolveFn: Function;
29+
30+
/** A policy that defines when to invoke the resolve, and whether to wait for async and unwrap the data */
31+
policy?: ResolvePolicy;
32+
33+
/**
34+
* The Dependency Injection tokens for dependencies of the [[resolveFn]].
35+
* The DI tokens are references to other `Resolvables`, or to global services.
36+
*/
37+
deps?: any[];
38+
39+
/** Pre-resolved value. */
40+
data?: any
1141
}
1242

13-
// Defines the available policies and their ordinals.
14-
export enum ResolvePolicy {
15-
LAZY, // Lazy resolves are resolved before their state is entered.
16-
EAGER // Eager resolves are resolved before the transition starts.
17-
}
43+
/**
44+
* Defines how a resolve is processed during a transition
45+
*
46+
* @example
47+
* ```js
48+
*
49+
* // Fetched when the resolve's state is being entered.
50+
* // Wait for the promise to resolve.
51+
* var policy1 = { when: "LAZY", async: "WAIT" }
52+
*
53+
* // Fetched when the Transition is starting.
54+
* // Do not wait for the returned promise to resolve.
55+
* // Inject the raw promise/value
56+
* var policy2 = { when: "EAGER", async: "NOWAIT" }
57+
* ```
58+
*
59+
* The policy for a given Resolvable is merged from three sources (highest priority first):
60+
*
61+
* 1) Individual resolve definition
62+
* 2) State definition
63+
* 3) Global default
64+
*
65+
* @example
66+
* ```js
67+
*
68+
* // Wait for an Observable to emit one item.
69+
* // Since `wait` is not specified, it uses the `wait`
70+
* // policy defined on the state, or the global default
71+
* // if no `wait` policy is defined on the state
72+
* var myResolvablePolicy = { async: "RXWAIT" }
73+
* ```
74+
*/
75+
export interface ResolvePolicy {
76+
/**
77+
* Defines when a Resolvable is resolved (fetched) during a transition
78+
*
79+
* - `LAZY` (default) resolved as the resolve's state is being entered
80+
* - `EAGER` resolved as the transition is starting
81+
*/
82+
when?: PolicyWhen;
83+
84+
/**
85+
* Determines the unwrapping behavior of asynchronous resolve values.
86+
*
87+
* - `WAIT` (default) if a promise is returned from the resolveFn, wait for the promise before proceeding
88+
* - `NOWAIT` if a promise is returned from the resolve, do not wait for the promise.
89+
* The promise will not be unwrapped.
90+
* The promise itself will be provided when the resolve is injected or bound elsewhere.
91+
* - `RXWAIT` When an Observable is returned from the resolveFn, wait until the Observable emits at least one item.
92+
* The Observable item will not be unwrapped.
93+
* The Observable stream itself will be provided when the resolve is injected or bound elsewhere.
94+
*/
95+
async?: PolicyAsync;
96+
}
97+
98+
export type PolicyWhen = "LAZY" | "EAGER" ;
99+
export type PolicyAsync = "WAIT" | "NOWAIT" | "RXWAIT" ;
100+
101+
export let resolvePolicies = {
102+
when: {
103+
LAZY: "LAZY",
104+
EAGER: "EAGER"
105+
},
106+
async: {
107+
WAIT: "WAIT",
108+
NOWAIT: "NOWAIT",
109+
RXWAIT: "RXWAIT"
110+
}
111+
};

0 commit comments

Comments
 (0)