UNPKG

ui-router-core

Version:

UI-Router Core: Framework agnostic, State-based routing for JavaScript Single Page Apps

131 lines 5.74 kB
/** * @coreapi * @module resolve */ /** for typedoc */ import { extend, identity } from "../common/common"; import { services } from "../common/coreservices"; import { trace } from "../common/trace"; import { stringify } from "../common/strings"; import { isFunction, isObject } from "../common/predicates"; // TODO: explicitly make this user configurable export var defaultResolvePolicy = { when: "LAZY", async: "WAIT" }; /** * The basic building block for the resolve system. * * Resolvables encapsulate a state's resolve's resolveFn, the resolveFn's declared dependencies, the wrapped (.promise), * and the unwrapped-when-complete (.data) result of the resolveFn. * * Resolvable.get() either retrieves the Resolvable's existing promise, or else invokes resolve() (which invokes the * resolveFn) and returns the resulting promise. * * Resolvable.get() and Resolvable.resolve() both execute within a context path, which is passed as the first * parameter to those fns. */ var Resolvable = (function () { function Resolvable(arg1, resolveFn, deps, policy, data) { this.resolved = false; this.promise = undefined; if (arg1 instanceof Resolvable) { extend(this, arg1); } else if (isFunction(resolveFn)) { if (arg1 == null || arg1 == undefined) throw new Error("new Resolvable(): token argument is required"); if (!isFunction(resolveFn)) throw new Error("new Resolvable(): resolveFn argument must be a function"); this.token = arg1; this.policy = policy; this.resolveFn = resolveFn; this.deps = deps || []; this.data = data; this.resolved = data !== undefined; this.promise = this.resolved ? services.$q.when(this.data) : undefined; } else if (isObject(arg1) && arg1.token && isFunction(arg1.resolveFn)) { var literal = arg1; return new Resolvable(literal.token, literal.resolveFn, literal.deps, literal.policy, literal.data); } } Resolvable.prototype.getPolicy = function (state) { var thisPolicy = this.policy || {}; var statePolicy = state && state.resolvePolicy || {}; return { when: thisPolicy.when || statePolicy.when || defaultResolvePolicy.when, async: thisPolicy.async || statePolicy.async || defaultResolvePolicy.async, }; }; /** * Asynchronously resolve this Resolvable's data * * Given a ResolveContext that this Resolvable is found in: * Wait for this Resolvable's dependencies, then invoke this Resolvable's function * and update the Resolvable's state */ Resolvable.prototype.resolve = function (resolveContext, trans) { var _this = this; var $q = services.$q; // Gets all dependencies from ResolveContext and wait for them to be resolved var getResolvableDependencies = function () { return $q.all(resolveContext.getDependencies(_this).map(function (resolvable) { return resolvable.get(resolveContext, trans); })); }; // Invokes the resolve function passing the resolved dependencies as arguments var invokeResolveFn = function (resolvedDeps) { return _this.resolveFn.apply(null, resolvedDeps); }; /** * For RXWAIT policy: * * Given an observable returned from a resolve function: * - enables .cache() mode (this allows multicast subscribers) * - then calls toPromise() (this triggers subscribe() and thus fetches) * - Waits for the promise, then return the cached observable (not the first emitted value). */ var waitForRx = function (observable$) { var cached = observable$.cache(1); return cached.take(1).toPromise().then(function () { return cached; }); }; // If the resolve policy is RXWAIT, wait for the observable to emit something. otherwise pass through. var node = resolveContext.findNode(this); var state = node && node.state; var maybeWaitForRx = this.getPolicy(state).async === "RXWAIT" ? waitForRx : identity; // After the final value has been resolved, update the state of the Resolvable var applyResolvedValue = function (resolvedValue) { _this.data = resolvedValue; _this.resolved = true; trace.traceResolvableResolved(_this, trans); return _this.data; }; // Sets the promise property first, then getsResolvableDependencies in the context of the promise chain. Always waits one tick. return this.promise = $q.when() .then(getResolvableDependencies) .then(invokeResolveFn) .then(maybeWaitForRx) .then(applyResolvedValue); }; /** * Gets a promise for this Resolvable's data. * * Fetches the data and returns a promise. * Returns the existing promise if it has already been fetched once. */ Resolvable.prototype.get = function (resolveContext, trans) { return this.promise || this.resolve(resolveContext, trans); }; Resolvable.prototype.toString = function () { return "Resolvable(token: " + stringify(this.token) + ", requires: [" + this.deps.map(stringify) + "])"; }; Resolvable.prototype.clone = function () { return new Resolvable(this); }; return Resolvable; }()); export { Resolvable }; Resolvable.fromData = function (token, data) { return new Resolvable(token, function () { return data; }, null, null, data); }; //# sourceMappingURL=resolvable.js.map