Skip to content

Commit b1379e6

Browse files
feat($state): add state params validation Closes #1433
feat($urlMatcherFactory): add function to get a RegExp Type
1 parent 3f60fbe commit b1379e6

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

src/state.js

+2
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
778778
}
779779
if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
780780
if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
781+
if (!toState.params.$$validates(toParams)) return TransitionFailed;
782+
781783
var defaultParams = toState.params.$$values();
782784
toParams = extend(defaultParams, toParams);
783785
to = toState;

src/urlMatcherFactory.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ function UrlMatcher(pattern, config) {
9494
return result + flag + '(' + pattern + ')' + flag;
9595
}
9696

97+
function regexpType(regexp) {
98+
var type = new Type({
99+
pattern: new RegExp(regexp),
100+
is: function(value) { return type.pattern.exec(type.encode(value)); }
101+
});
102+
return type;
103+
}
104+
97105
this.source = pattern;
98106

99107
// Split into static segments separated by path parameter placeholders.
@@ -104,7 +112,7 @@ function UrlMatcher(pattern, config) {
104112
id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
105113
regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*');
106114
segment = pattern.substring(last, m.index);
107-
type = this.$types[regexp] || new Type({ pattern: new RegExp(regexp) });
115+
type = this.$types[regexp] || regexpType(regexp);
108116
cfg = config.params[id];
109117

110118
if (segment.indexOf('?') >= 0) break; // we're into the search part

test/stateSpec.js

+27
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ describe('state', function () {
9696
.state('badParam', {
9797
url: "/bad/{param:int}"
9898
})
99+
.state('badParam2', {
100+
url: "/bad2/{param:[0-9]{5}}"
101+
})
99102

100103
.state('first', { url: '^/first/subpath' })
101104
.state('second', { url: '^/second' })
@@ -755,6 +758,7 @@ describe('state', function () {
755758
'about.sidebar',
756759
'about.sidebar.item',
757760
'badParam',
761+
'badParam2',
758762
'dynamicController',
759763
'first',
760764
'home',
@@ -875,6 +879,29 @@ describe('state', function () {
875879
$rootScope.$apply();
876880
expect($state.current.name).toBe("about");
877881
}));
882+
883+
it('should ignore bad state parameters', inject(function ($state, $rootScope, $location, $stateParams) {
884+
$state.go("badParam", { param: 5 });
885+
$rootScope.$apply();
886+
expect($state.current.name).toBe("badParam");
887+
expect($stateParams).toEqual({param: 5});
888+
889+
$state.go("badParam2", { param: '12345' }); // must be 5 digits
890+
$rootScope.$apply();
891+
expect($state.current.name).toBe("badParam2");
892+
893+
$state.go("about");
894+
$rootScope.$apply();
895+
expect($state.current.name).toBe('about');
896+
897+
$state.go("badParam", { param: 'foo' });
898+
$rootScope.$apply();
899+
expect($state.current.name).toBe("about");
900+
901+
$state.go("badParam2", { param: '1234' }); // must be 5 digits
902+
$rootScope.$apply();
903+
expect($state.current.name).toBe("about");
904+
}));
878905
});
879906

880907
it('should revert to last known working url on state change failure', inject(function ($state, $rootScope, $location, $q) {

0 commit comments

Comments
 (0)