Skip to content

Commit

Permalink
feat(UrlMatcher): injectable functions as defaults
Browse files Browse the repository at this point in the history
Default parameter values may now be specified as injectable functions.
  • Loading branch information
nateabele committed Apr 19, 2014
1 parent 63607bd commit 00966ec
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
29 changes: 25 additions & 4 deletions src/urlMatcherFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,19 @@ function UrlMatcher(pattern, config) {
segments = this.segments = [],
params = this.params = {};

/**
* [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the
* default value, which may be the result of an injectable function.
*/
function $value(value) {
/*jshint validthis: true */
return isDefined(value) ? this.type.decode(value) : $UrlMatcherFactory.$$getDefaultValue(this);
}

function addParameter(id, type, config) {
if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
params[id] = extend({ type: type || new Type() }, config);
params[id] = extend({ type: type || new Type(), $value: $value }, config);
}

function quoteRegExp(string, pattern, isOptional) {
Expand Down Expand Up @@ -216,7 +225,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
for (i = 0; i < nPath; i++) {
param = params[i];
cfg = this.params[param];
values[param] = isDefined(m[i + 1]) ? cfg.type.decode(m[i + 1]) : cfg.value;
values[param] = cfg.$value(m[i + 1]);
}
for (/**/; i < nTotal; i++) {
param = params[i];
Expand Down Expand Up @@ -483,6 +492,19 @@ function $UrlMatcherFactory() {
};
}

function isInjectable(value) {
return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));
}

/**
* [Internal] Get the default value of a parameter, which may be an injectable function.
*/
$UrlMatcherFactory.$$getDefaultValue = function(config) {
if (!isInjectable(config.value)) return config.value;
if (!injector) throw new Error("Injectable functions cannot be called at configuration time");
return injector.invoke(config.value);
};

/**
* @ngdoc function
* @name ui.router.util.$urlMatcherFactory#caseInsensitive
Expand Down Expand Up @@ -683,8 +705,7 @@ function $UrlMatcherFactory() {
if (UrlMatcher.prototype.$types[type.name]) {
throw new Error("A type named '" + type.name + "' has already been defined.");
}
var isAnnotated = isFunction(type.def) || isArray(type.def);
var def = new Type(isAnnotated ? injector.invoke(type.def) : type.def);
var def = new Type(isInjectable(type.def) ? injector.invoke(type.def) : type.def);
UrlMatcher.prototype.$types[type.name] = def;
});
}
Expand Down
27 changes: 26 additions & 1 deletion test/urlMatcherFactorySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,38 @@ describe("urlMatcherFactory", function () {
expect(m.exec("/foo")).toEqual({ foo: "bar" });
});

it("should populate default values for query params", function() {
it("should populate query params", function() {
var defaults = { order: "name", limit: 25, page: 1 };
var m = new UrlMatcher('/foo?order&limit&page', {
params: defaults
});
expect(m.exec("/foo")).toEqual(defaults);
});

it("should allow function-calculated values", function() {
var m = new UrlMatcher('/foo/:bar', {
params: {
bar: function() {
return "Value from bar()";
}
}
});
expect(m.exec('/foo').bar).toBe("Value from bar()");
});

it("should allow injectable functions", inject(function($stateParams) {
var m = new UrlMatcher('/users/:user', {
params: {
user: function($stateParams) {
return $stateParams.user;
}
}
});
var user = { name: "Bob" };

$stateParams.user = user;
expect(m.exec('/users').user).toBe(user);
}));
});
});

Expand Down

0 comments on commit 00966ec

Please sign in to comment.