From a4fe51da3ba0dc297ecd389e230d6664f250c9a6 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Tue, 20 Mar 2012 00:38:08 -0700 Subject: [PATCH] feat($route): when matching consider trailing slash as optional This makes for a much more flexible route matching: - route /foo matches /foo and redirects /foo/ to /foo - route /bar/ matches /bar/ and redirects /bar to /bar/ Closes #784 --- src/service/route.js | 15 ++++++++++++++- test/service/routeSpec.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/service/route.js b/src/service/route.js index 9748de69f80d..2b9d187adabe 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -18,7 +18,10 @@ function $RouteProvider(){ * @name angular.module.ng.$routeProvider#when * @methodOf angular.module.ng.$routeProvider * - * @param {string} path Route path (matched against `$location.hash`) + * @param {string} path Route path (matched against `$location.path`). If `$location.path` + * contains redudant trailing slash or is missing one, the route will still match and the + * `$location.path` will be updated to add or drop the trailing slash to exacly match the + * route definition. * @param {Object} route Mapping information to be assigned to `$route.current` on route * match. * @@ -57,6 +60,16 @@ function $RouteProvider(){ var routeDef = routes[path]; if (!routeDef) routeDef = routes[path] = {reloadOnSearch: true}; if (route) extend(routeDef, route); // TODO(im): what the heck? merge two route definitions? + + // create redirection for trailing slashes + if (path) { + var redirectPath = (path[path.length-1] == '/') + ? path.substr(0, path.length-1) + : path +'/'; + + routes[redirectPath] = {redirectTo: path}; + } + return routeDef; }; diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js index 6b8127a0a147..88e54b9aaa35 100644 --- a/test/service/routeSpec.js +++ b/test/service/routeSpec.js @@ -168,6 +168,36 @@ describe('$route', function() { }); + it('should match route with and without trailing slash', function() { + module(function($routeProvider){ + $routeProvider.when('/foo', {template: 'foo.html'}); + $routeProvider.when('/bar/', {template: 'bar.html'}); + }); + + inject(function($route, $location, $rootScope) { + $location.path('/foo'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.template).toBe('foo.html'); + + $location.path('/foo/'); + $rootScope.$digest(); + expect($location.path()).toBe('/foo'); + expect($route.current.template).toBe('foo.html'); + + $location.path('/bar'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/'); + expect($route.current.template).toBe('bar.html'); + + $location.path('/bar/'); + $rootScope.$digest(); + expect($location.path()).toBe('/bar/'); + expect($route.current.template).toBe('bar.html'); + }); + }); + + describe('redirection', function() { it('should support redirection via redirectTo property by updating $location', function() { module(function($routeProvider) {