-
Notifications
You must be signed in to change notification settings - Fork 3k
fix($state): populate default params in .transitionTo. closes #1396 #1432
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
christopherthielen
wants to merge
8
commits into
angular-ui:master
from
christopherthielen:issue-1396-b
Closed
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
967e49b
fix($urlMatcherFactory): Made a Params class
christopherthielen 2f7eb4f
fix($state): make ownParams and params use Param type
christopherthielen 75a0ed3
feat($urlMatcherFactory): add Param.isOptional
christopherthielen 2541023
fix($urlMatcherFactory): always initalize $urlMatcherFactory at runtime.
christopherthielen 9499093
feat($urlMatcherFactory): add ParamSet class
christopherthielen 231b221
fix(): fix 86137values logic
christopherthielen 0630562
fix(): use ownParams.86137keys()
christopherthielen a31c381
fix(): populate default params in .transitionTo. closes #1396
christopherthielen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,7 +60,7 @@ | |
* @returns {Object} New `UrlMatcher` object | ||
*/ | ||
function UrlMatcher(pattern, config) { | ||
config = angular.isObject(config) ? config : {}; | ||
config = extend({ params: {} }, isObject(config) ? config : {}); | ||
|
||
// Find all placeholders and create a compiled pattern, using either classic or curly syntax: | ||
// '*' name | ||
|
@@ -78,21 +78,13 @@ function UrlMatcher(pattern, config) { | |
var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g, | ||
compiled = '^', last = 0, m, | ||
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); | ||
} | ||
params = this.params = new $$UrlMatcherFactoryProvider.ParamSet(); | ||
|
||
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(), $value: $value }, config); | ||
params[id] = new $$UrlMatcherFactoryProvider.Param(id, type, config); | ||
return params[id]; | ||
} | ||
|
||
function quoteRegExp(string, pattern, isOptional) { | ||
|
@@ -102,12 +94,6 @@ function UrlMatcher(pattern, config) { | |
return result + flag + '(' + pattern + ')' + flag; | ||
} | ||
|
||
function paramConfig(param) { | ||
if (!config.params || !config.params[param]) return {}; | ||
var cfg = config.params[param]; | ||
return isObject(cfg) ? cfg : { value: cfg }; | ||
} | ||
|
||
this.source = pattern; | ||
|
||
// Split into static segments separated by path parameter placeholders. | ||
|
@@ -119,12 +105,12 @@ function UrlMatcher(pattern, config) { | |
regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*'); | ||
segment = pattern.substring(last, m.index); | ||
type = this.$types[regexp] || new Type({ pattern: new RegExp(regexp) }); | ||
cfg = paramConfig(id); | ||
cfg = config.params[id]; | ||
|
||
if (segment.indexOf('?') >= 0) break; // we're into the search part | ||
|
||
compiled += quoteRegExp(segment, type.$subPattern(), isDefined(cfg.value)); | ||
addParameter(id, type, cfg); | ||
var param = addParameter(id, type, cfg); | ||
compiled += quoteRegExp(segment, type.$subPattern(), param.isOptional); | ||
segments.push(segment); | ||
last = placeholder.lastIndex; | ||
} | ||
|
@@ -140,7 +126,7 @@ function UrlMatcher(pattern, config) { | |
|
||
// Allow parameters to be separated by '?' as well as '&' to make concat() easier | ||
forEach(search.substring(1).split(/[&?]/), function(key) { | ||
addParameter(key, null, paramConfig(key)); | ||
addParameter(key, null, config.params[key]); | ||
}); | ||
} else { | ||
this.sourcePath = pattern; | ||
|
@@ -180,7 +166,7 @@ UrlMatcher.prototype.concat = function (pattern, config) { | |
// 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 $$UrlMatcherFactoryProvider.compile(this.sourcePath + pattern + this.sourceSearch, config); | ||
return $$UrlMatcherFactoryProvider.compile(this.sourcePath + pattern + this.sourceSearch, config); | ||
}; | ||
|
||
UrlMatcher.prototype.toString = function () { | ||
|
@@ -216,21 +202,19 @@ UrlMatcher.prototype.exec = function (path, searchParams) { | |
if (!m) return null; | ||
searchParams = searchParams || {}; | ||
|
||
var params = this.parameters(), nTotal = params.length, | ||
var paramNames = this.parameters(), nTotal = paramNames.length, | ||
nPath = this.segments.length - 1, | ||
values = {}, i, cfg, param; | ||
values = {}, i, cfg, paramName; | ||
|
||
if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'"); | ||
|
||
for (i = 0; i < nPath; i++) { | ||
param = params[i]; | ||
cfg = this.params[param]; | ||
values[param] = cfg.$value(m[i + 1]); | ||
paramName = paramNames[i]; | ||
values[paramName] = this.params[paramName].value(m[i + 1]); | ||
} | ||
for (/**/; i < nTotal; i++) { | ||
param = params[i]; | ||
cfg = this.params[param]; | ||
values[param] = cfg.$value(searchParams[param]); | ||
paramName = paramNames[i]; | ||
values[paramName] = this.params[paramName].value(searchParams[paramName]); | ||
} | ||
|
||
return values; | ||
|
@@ -265,15 +249,7 @@ UrlMatcher.prototype.parameters = function (param) { | |
* @returns {boolean} Returns `true` if `params` validates, otherwise `false`. | ||
*/ | ||
UrlMatcher.prototype.validates = function (params) { | ||
var result = true, isOptional, cfg, self = this; | ||
|
||
forEach(params, function(val, key) { | ||
if (!self.params[key]) return; | ||
cfg = self.params[key]; | ||
isOptional = !val && isDefined(cfg.value); | ||
result = result && (isOptional || cfg.type.is(val)); | ||
}); | ||
return result; | ||
return this.params.$$validates(params); | ||
}; | ||
|
||
/** | ||
|
@@ -717,7 +693,86 @@ function $UrlMatcherFactory() { | |
UrlMatcher.prototype.$types[type.name] = def; | ||
}); | ||
} | ||
|
||
this.Param = function Param(id, type, config) { | ||
var self = this; | ||
var defaultValueConfig = getDefaultValueConfig(config); | ||
config = config || {}; | ||
type = getType(config, type); | ||
|
||
function getDefaultValueConfig(config) { | ||
var keys = isObject(config) ? objectKeys(config) : []; | ||
var isShorthand = keys.indexOf("value") === -1 && keys.indexOf("type") === -1; | ||
var configValue = isShorthand ? config : config.value; | ||
return { | ||
fn: isInjectable(configValue) ? configValue : function () { return configValue; }, | ||
value: configValue | ||
}; | ||
} | ||
|
||
function getType(config, urlType) { | ||
if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations."); | ||
if (urlType && !config.type) return urlType; | ||
return config.type instanceof Type ? config.type : new Type(config.type || {}); | ||
} | ||
|
||
/** | ||
* [Internal] Get the default value of a parameter, which may be an injectable function. | ||
*/ | ||
function $$getDefaultValue() { | ||
if (!injector) throw new Error("Injectable functions cannot be called at configuration time"); | ||
return injector.invoke(defaultValueConfig.fn); | ||
} | ||
|
||
/** | ||
* [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) { | ||
return isDefined(value) ? self.type.decode(value) : $$getDefaultValue(); | ||
} | ||
|
||
extend(this, { | ||
id: id, | ||
type: type, | ||
config: config, | ||
dynamic: undefined, | ||
isOptional: defaultValueConfig.value !== undefined, | ||
value: $value | ||
}); | ||
}; | ||
|
||
function ParamSet(params) { | ||
extend(this, params || {}); | ||
} | ||
|
||
ParamSet.prototype = { | ||
$$keys: function () { | ||
return protoKeys(this, ["$$keys", "$$values", "$$validates"]); | ||
}, | ||
$$values: function(paramValues) { | ||
var values = {}, self = this; | ||
forEach(self.$$keys(), function(key) { | ||
values[key] = self[key].value(paramValues && paramValues[key]); | ||
}); | ||
return values; | ||
}, | ||
$$validates: function $$validate(paramValues) { | ||
var result = true, isOptional, param, self = this; | ||
|
||
forEach(paramValues, function (val, key) { | ||
if (!self[key]) return; | ||
param = self[key]; | ||
isOptional = !val && param.isOptional; | ||
result = result && (isOptional || param.type.is(val)); | ||
}); | ||
return result; | ||
} | ||
}; | ||
|
||
this.ParamSet = ParamSet; | ||
} | ||
|
||
// Register as a provider so it's available to other providers | ||
angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory); | ||
angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a pattern I use in ui-router-extras to make sure that provider.$get() is called |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not yet satisfied with this logic. this means
paramName: undefined
is not optional butparamName: null
is optional