Skip to content

Typed and optional parameters #1032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Apr 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
450b1f0
feat($urlMatcherFactory): implement type support
nateabele Mar 26, 2014
1ebed37
fix($urlMatcherFactory): syntax
nateabele Mar 26, 2014
aeb6d9b
chore($urlMatcherFactory): clean up test defs
nateabele Mar 26, 2014
b7f074f
feat($urlMatcherFactory): date type support
nateabele Mar 26, 2014
8939d05
feat($state): allow parameters to pass unharmed
nateabele Mar 26, 2014
d8f124c
feat($urlMatcherFactory): fail on bad parameters
nateabele Mar 26, 2014
d48505c
feat($urlRouter): force URLs to have valid params
nateabele Mar 26, 2014
c27a0ee
chore($state): validate rejection of bad params
nateabele Mar 27, 2014
07b3029
feat(UrlMatcher): add per-param config support
nateabele Apr 16, 2014
27d382c
test(uiSref): remove unused dependencies
nateabele Apr 16, 2014
c72d8ce
feat($urlRouter): defer URL change interception
nateabele Apr 16, 2014
ad07a8d
style(UrlMatcher): semantic and formatting fixes
nateabele Apr 16, 2014
a3e2136
feat(UrlMatcher): implement non-strict matching
nateabele Apr 16, 2014
32b27db
feat(UrlMatcher): validates whole interface
nateabele Apr 16, 2014
7057de4
test($urlRouter): update to UrlMatcher interface
nateabele Apr 16, 2014
bba61cd
doc($urlRouter): document href() method
nateabele Apr 17, 2014
101012e
perf($urlRouter): only call $location.port() once
nateabele Apr 17, 2014
5b72430
feat(UrlMatcher): allow shorthand definitions
nateabele Apr 17, 2014
a472b30
feat(UrlMatcher): default values & type decoding for query params
nateabele Apr 17, 2014
67be0bd
docs($urlMatcherFactory): Type object & formatting
nateabele Apr 17, 2014
91f75ae
fix($urlMatcherFactory): detect injected functions
nateabele Apr 17, 2014
b881c72
chore(common): unique name for internal function
nateabele Apr 17, 2014
63607bd
fix(UrlMatcher): don't decode default values
nateabele Apr 19, 2014
00966ec
feat(UrlMatcher): injectable functions as defaults
nateabele Apr 19, 2014
7ef8f3c
test(UrlMatcher): optional params between statics
nateabele Apr 19, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions src/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function ancestors(first, second) {
* @param {Object} object A JavaScript object.
* @return {Array} Returns the keys of the object as an array.
*/
function keys(object) {
function objectKeys(object) {
if (Object.keys) {
return Object.keys(object);
}
Expand Down Expand Up @@ -96,8 +96,9 @@ function inheritParams(currentParams, newParams, $current, $to) {
var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];

for (var i in parents) {
if (!parents[i].params || !parents[i].params.length) continue;
parentParams = parents[i].params;
if (!parents[i].params) continue;
parentParams = objectKeys(parents[i].params);
if (!parentParams.length) continue;

for (var j in parentParams) {
if (arraySearch(inheritList, parentParams[j]) >= 0) continue;
Expand All @@ -108,23 +109,6 @@ function inheritParams(currentParams, newParams, $current, $to) {
return extend({}, inherited, newParams);
}

/**
* Normalizes a set of values to string or `null`, filtering them by a list of keys.
*
* @param {Array} keys The list of keys to normalize/return.
* @param {Object} values An object hash of values to normalize.
* @return {Object} Returns an object hash of normalized string values.
*/
function normalize(keys, values) {
var normalized = {};

forEach(keys, function (name) {
var value = values[name];
normalized[name] = (value != null) ? String(value) : null;
});
return normalized;
}

/**
* Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
*
Expand Down
53 changes: 28 additions & 25 deletions src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,14 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {

// Build a URLMatcher if necessary, either via a relative or absolute URL
url: function(state) {
var url = state.url;
var url = state.url, config = { params: state.params || {} };

if (isString(url)) {
if (url.charAt(0) == '^') {
return $urlMatcherFactory.compile(url.substring(1));
}
return (state.parent.navigable || root).url.concat(url);
if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);
return (state.parent.navigable || root).url.concat(url, config);
}

if ($urlMatcherFactory.isMatcher(url) || url == null) {
return url;
}
if (!url || $urlMatcherFactory.isMatcher(url)) return url;
throw new Error("Invalid url '" + url + "' in state '" + state + "'");
},

Expand All @@ -71,10 +67,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
// Derive parameters for this state and ensure they're a super-set of parent's parameters
params: function(state) {
if (!state.params) {
return state.url ? state.url.parameters() : state.parent.params;
return state.url ? state.url.params : state.parent.params;
}
if (!isArray(state.params)) throw new Error("Invalid params in state '" + state + "'");
if (state.url) throw new Error("Both params and url specicified in state '" + state + "'");
return state.params;
},

Expand All @@ -94,16 +88,18 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
},

ownParams: function(state) {
state.params = state.params || {};

if (!state.parent) {
return state.params;
return objectKeys(state.params);
}
var paramNames = {}; forEach(state.params, function (p) { paramNames[p] = true; });
var paramNames = {}; forEach(state.params, function (v, k) { paramNames[k] = true; });

forEach(state.parent.params, function (p) {
if (!paramNames[p]) {
throw new Error("Missing required parameter '" + p + "' in state '" + state.name + "'");
forEach(state.parent.params, function (v, k) {
if (!paramNames[k]) {
throw new Error("Missing required parameter '" + k + "' in state '" + state.name + "'");
}
paramNames[p] = false;
paramNames[k] = false;
});
var ownParams = [];

Expand Down Expand Up @@ -782,8 +778,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
toState = findState(to, options.relative);

if (!isDefined(toState)) {
if (options.relative) throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
throw new Error("No such state '" + to + "'");
if (!options.relative) throw new Error("No such state '" + to + "'");
throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'");
}
}
if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
Expand All @@ -808,14 +804,14 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
// TODO: We may not want to bump 'transition' if we're called from a location change
// that we've initiated ourselves, because we might accidentally abort a legitimate
// transition initiated from code?
if (shouldTriggerReload(to, from, locals, options) ) {
if (shouldTriggerReload(to, from, locals, options)) {
if (to.self.reloadOnSearch !== false) $urlRouter.update();
$state.transition = null;
return $q.when($state.current);
}

// Normalize/filter parameters before we pass them to event handlers etc.
toParams = normalize(to.params, toParams || {});
// Filter parameters before we pass them to event handlers etc.
toParams = filterByKeys(objectKeys(to.params), toParams || {});

// Broadcast start event and cancel the transition if requested
if (options.notify) {
Expand Down Expand Up @@ -1090,7 +1086,12 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
* @returns {string} compiled state url
*/
$state.href = function href(stateOrName, params, options) {
options = extend({ lossy: true, inherit: false, absolute: false, relative: $state.$current }, options || {});
options = extend({
lossy: true,
inherit: false,
absolute: false,
relative: $state.$current
}, options || {});

var state = findState(stateOrName, options.relative);

Expand All @@ -1102,7 +1103,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
if (!nav || !nav.url) {
return null;
}
return $urlRouter.href(nav.url, normalize(state.params, params || {}), { absolute: options.absolute });
return $urlRouter.href(nav.url, filterByKeys(objectKeys(state.params), params || {}), {
absolute: options.absolute
});
};

/**
Expand Down Expand Up @@ -1132,7 +1135,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
// necessary. In addition to being available to the controller and onEnter/onExit callbacks,
// we also need $stateParams to be available for any $injector calls we make during the
// dependency resolution process.
var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params, params);
var $stateParams = (paramsAreFiltered) ? params : filterByKeys(objectKeys(state.params), params);
var locals = { $stateParams: $stateParams };

// Resolve 'global' dependencies for the state, i.e. those not specific to a view.
Expand Down
Loading