I'm coming from the Asp.net MVC world where route constraints are really useful. I'm currently developing an Angular JS SPA that incorporates client side routing.
I would also like to add parameter constraints to my client-side routes as in:
$.routeProvider.when("/post/:id/:name?")
where I'd like to constrain my :id parameter to only be valid when these are numbers.
I haven't found anything similar in Angular Docs (which are horrible to say the least). Can it be done? And maybe also parameter defaults?
There's no built-in way to set route constraints, but you can do it pretty easily yourself by using the resolve feature.
module.config(function ($routeProvider) {
$routeProvider.when('/post/:id/:name', {
controller: 'PostCtrl',
resolve: {
id: function ($q, $route) {
var deferred = $q.defer(),
id = parseInt($route.current.params.id, 10);
if (!isNaN(id)) {
deferred.resolve(id);
} else {
deferred.reject('Id is not a number');
}
return deferred.promise;
},
// This isn't really needed, you can extract the name using
// $routeParams.name as you usually would in the controller.
name: function ($route) {
return $route.current.params.name;
}
}
});
});
By doing it this way you can inject id and name into PostCtrl:
module.controller('PostCtrl', function ($scope, $routeParams, id, name) {
});
id in this case will be a number. You can of course also use $routeParams.id and $routeParams.name but those are always strings.
In case something else than a number is passed, then the promise is rejected and you need to handle that, usually in the 'MainCtrl' or 'AppCtrl' if you're doing a SPA.
module.controller('AppCtrl', function ($scope, $log) {
$scope.$on('$routeChangeError', function (ev, current, previous, rejection) {
$log.error('Error changing route: ' + rejection);
// Will print: Error changing route: Id is not a number
});
});
Update
You can use resolve in combination with the $routeChangeError event to validate the route and redirect on error. The resolve properties are always run, even if they aren't injected in the controller.
resolve: {
validation: function ($q, $route) {
var deferred = $q.defer(),
id = parseInt($route.current.params.id, 10);
if (!isNaN(id)) {
deferred.resolve();
} else {
deferred.reject('VALIDATION FAILED');
}
return deferred.promise;
}
}
In your home controller simply add:
module.controller('AppCtrl', function ($scope, $location) {
$scope.$on('$routeChangeError', function (ev, current, previous, rejection) {
if (rejection === 'VALIDATION FAILED') {
$location.path('/home');
}
});
});
This is a quite hacky way to solve it and you might be better of using ui-router (I haven't tried that one). Unfortunately it's not possible to listen to $routeChangeStart and abort if needed. Otherwise this could've been solved a lot nicer.
Angular route source change - most transparent constraints
There's a pull request in AngularJS source (made by me) that adds regular expression constraints to route parameters. It works a simple as providing this kind of route definition:
/:parameter:regularexpression
An example would be
/profile/:id:[1-9]\\d*/edit
This means that id has to be a number not starting with a 0.
Additional requirements
There are of course some additional requirements to these parameters:
parameter can't be optional or greedy - if it ends with
?or*this character will become part of regular expression (as these are both regular expression tokens with their respective meaningregular expression constraint can't use regular expression capture groups as
(and)get escaped as part of regular expression constraint - this already works this way so if your parameter name includes(or)they will both be escapedregular expression constraint can't include
/as these are route segment delimiters
One way is to use ui-router, which allows to specify url using regex.
来源:https://stackoverflow.com/questions/21205937/angular-route-parameters-contraints