Skip to content

Add possibility to make states not to behave strict and allow optional params #755

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

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 3 additions & 4 deletions src/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ function inheritParams(currentParams, newParams, $current, $to) {
function normalize(keys, values) {
var normalized = {};

forEach(keys, function (name) {
var value = values[name];
forEach(values, function (value, name) {
normalized[name] = (value != null) ? String(value) : null;
});
return normalized;
Expand Down Expand Up @@ -175,7 +174,7 @@ angular.module('ui.router.util', ['ng']);
/**
* @ngdoc overview
* @name ui.router.router
*
*
* @requires ui.router.util
*
* @description
Expand All @@ -186,7 +185,7 @@ angular.module('ui.router.router', ['ui.router.util']);
/**
* @ngdoc overview
* @name ui.router.router
*
*
* @requires ui.router.router
* @requires ui.router.util
*
Expand Down
14 changes: 7 additions & 7 deletions src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $

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

if ($urlMatcherFactory.isMatcher(url) || url == null) {
Expand Down Expand Up @@ -202,7 +202,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
// Register the state in the global state list and with $urlRouter if necessary.
if (!state[abstractKey] && state.url) {
$urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
if ($state.$current.navigable != state || !equalForKeys($match, $stateParams, state.ownParams)) {
$state.transitionTo(state, $match, { location: false });
}
}]);
Expand Down Expand Up @@ -831,10 +831,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
url = "#" + $locationProvider.hashPrefix() + url;
}
if (options.absolute && url) {
url = $location.protocol() + '://' +
$location.host() +
($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) +
(!$locationProvider.html5Mode() && url ? '/' : '') +
url = $location.protocol() + '://' +
$location.host() +
($location.port() == 80 || $location.port() == 443 ? '' : ':' + $location.port()) +
(!$locationProvider.html5Mode() && url ? '/' : '') +
url;
}
return url;
Expand Down
47 changes: 35 additions & 12 deletions src/urlMatcherFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* of search parameters. Multiple search parameter names are separated by '&'. Search parameters
* do not influence whether or not a URL is matched, but their values are passed through into
* the matched parameters returned by {@link UrlMatcher#exec exec}.
*
*
* Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
* syntax, which optionally allows a regular expression for the parameter to be specified:
*
Expand All @@ -15,13 +15,13 @@
* curly braces, they must be in matched pairs or escaped with a backslash.
*
* Parameter names may contain only word characters (latin letters, digits, and underscore) and
* must be unique within the pattern (across both path and search parameters). For colon
* must be unique within the pattern (across both path and search parameters). For colon
* placeholders or curly placeholders without an explicit regexp, a path parameter matches any
* number of characters other than '/'. For catch-all placeholders the path parameter matches
* any number of characters.
*
*
* ### Examples
*
*
* * '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for
* trailing slashes, and patterns have to match the entire path, not just a prefix.
* * '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
Expand All @@ -36,12 +36,13 @@
*
* @constructor
* @param {string} pattern the pattern to compile into a matcher.
* @param {boolean} strict the formatting and matching should be strict.
*
* @property {string} prefix A static prefix of this pattern. The matcher guarantees that any
* URL matching this matcher (i.e. any string for which {@link UrlMatcher#exec exec()} returns
* non-null) will start with this prefix.
*/
function UrlMatcher(pattern) {
function UrlMatcher(pattern, strict) {

// Find all placeholders and create a compiled pattern, using either classic or curly syntax:
// '*' name
Expand Down Expand Up @@ -73,6 +74,7 @@ function UrlMatcher(pattern) {
}

this.source = pattern;
this.strict = typeof strict === 'boolean' ? strict : true;

// Split into static segments separated by path parameter placeholders.
// The number of segments is always 1 more than the number of parameters.
Expand Down Expand Up @@ -123,13 +125,14 @@ function UrlMatcher(pattern) {
* ```
*
* @param {string} pattern The pattern to append.
* @param {boolean} strict the formatting and matching should be strict.
* @return {UrlMatcher} A matcher for the concatenated pattern.
*/
UrlMatcher.prototype.concat = function (pattern) {
UrlMatcher.prototype.concat = function (pattern, strict) {
// Because order of search parameters is irrelevant, we can add our own search
// parameters to the end of the new pattern. Parse the new pattern by itself
// and then join the bits together, but it's much easier to do this on a string level.
return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch);
return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, strict);
};

UrlMatcher.prototype.toString = function () {
Expand Down Expand Up @@ -166,6 +169,10 @@ UrlMatcher.prototype.exec = function (path, searchParams) {
for (i=0; i<nPath; i++) values[params[i]] = m[i+1];
for (/**/; i<nTotal; i++) values[params[i]] = searchParams[params[i]];

if (!this.strict) {
angular.extend(values, searchParams);
}

return values;
};

Expand Down Expand Up @@ -197,22 +204,37 @@ UrlMatcher.prototype.format = function (values) {
if (!values) return segments.join('');

var nPath = segments.length-1, nTotal = params.length,
result = segments[0], i, search, value;
result = segments[0], i, search, value,
clonedValues = angular.extend({}, values), appendToSearch = function(key, value) {
result += (search ? '&' : '?') + key + '=' + encodeURIComponent(value);
search = true;
};

for (i=0; i<nPath; i++) {
value = values[params[i]];
// TODO: Maybe we should throw on null here? It's not really good style to use '' and null interchangeabley
if (value != null) result += encodeURIComponent(value);
result += segments[i+1];
delete clonedValues[params[i]];
}
for (/**/; i<nTotal; i++) {
value = values[params[i]];
if (value != null) {
result += (search ? '&' : '?') + params[i] + '=' + encodeURIComponent(value);
search = true;
appendToSearch(params[i], value);
}
delete clonedValues[params[i]];
}

if (!this.strict) {
var key;
for (key in clonedValues) {
if (clonedValues.hasOwnProperty(key)) {
value = clonedValues[key];
appendToSearch(key, value);
}
}
}

return result;
};

Expand All @@ -229,10 +251,11 @@ function $UrlMatcherFactory() {
* @name $urlMatcherFactory#compile
* @methodOf $urlMatcherFactory
* @param {string} pattern The URL pattern.
* @param {boolean} strict the formatting and matching should be strict.
* @return {UrlMatcher} The UrlMatcher.
*/
this.compile = function (pattern) {
return new UrlMatcher(pattern);
this.compile = function (pattern, strict) {
return new UrlMatcher(pattern, strict);
};

/**
Expand Down