From 86321d1f5722e0aefcdbe8f3e5a14bd15d4caecb Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Mon, 7 Feb 2011 14:32:28 -0800 Subject: add support for hashSearch redirection and custom redirection functions --- src/services.js | 59 +++++++++++++++++++++++++++++++++++----------------- test/servicesSpec.js | 43 +++++++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/services.js b/src/services.js index 9dfdd35e..be5189d1 100644 --- a/src/services.js +++ b/src/services.js @@ -748,13 +748,23 @@ angularServiceInject('$route', function(location, $updateView) { * Object properties: * * - `controller` – `{function()=}` – Controller fn that should be associated with newly - * created scope. + * created scope. * - `template` – `{string=}` – path to an html template that should be used by - * {@link angular.widget.ng:view ng:view} or - * {@link angular.widget.ng:include ng:include} widgets. - * - `redirectTo` – {string=} – value to update - * {@link angular.service.$location $location} hash with and trigger route - * redirection. + * {@link angular.widget.ng:view ng:view} or + * {@link angular.widget.ng:include ng:include} widgets. + * - `redirectTo` – {(string|function())=} – value to update + * {@link angular.service.$location $location} hash with and trigger route redirection. + * + * If `redirectTo` is a function, it will be called with the following parameters: + * + * - `{Object.}` - route parameters extracted from the current + * `$location.hashPath` by applying the current route template. + * - `{string}` - current `$location.hash` + * - `{string}` - current `$location.hashPath` + * - `{string}` - current `$location.hashSearch` + * + * The custom `redirectTo` function is expected to return a string which will be used + * to update `$location.hash`. * * @returns {Object} route object * @@ -801,7 +811,7 @@ angularServiceInject('$route', function(location, $updateView) { } }; function updateRoute(){ - var childScope, routeParams, pathParams, redirectPath, segmentMatch, key; + var childScope, routeParams, pathParams, segmentMatch, key, redir; $route.current = _null; forEach(routes, function(rParams, rPath) { @@ -817,18 +827,29 @@ angularServiceInject('$route', function(location, $updateView) { if(routeParams) { if (routeParams.redirectTo) { - redirectPath = ''; - forEach(routeParams.redirectTo.split(':'), function(segment, i) { - if (i==0) { - redirectPath += segment; - } else { - segmentMatch = segment.match(/(\w+)(.*)/); - key = segmentMatch[1]; - redirectPath += pathParams[key] || location.hashSearch[key]; - redirectPath += segmentMatch[2] || ''; - } - }); - location.updateHash(redirectPath); + if (isString(routeParams.redirectTo)) { + // interpolate the redirectTo string + redir = {hashPath: '', + hashSearch: extend({}, location.hashSearch, pathParams)}; + + forEach(routeParams.redirectTo.split(':'), function(segment, i) { + if (i==0) { + redir.hashPath += segment; + } else { + segmentMatch = segment.match(/(\w+)(.*)/); + key = segmentMatch[1]; + redir.hashPath += pathParams[key] || location.hashSearch[key]; + redir.hashPath += segmentMatch[2] || ''; + delete redir.hashSearch[key]; + } + }); + } else { + // call custom redirectTo function + redir = {hash: routeParams.redirectTo(pathParams, location.hash, location.hashPath, + location.hashSearch)}; + } + + location.update(redir); $updateView(); //TODO this is to work around the $location<=>$browser issues return; } diff --git a/test/servicesSpec.js b/test/servicesSpec.js index 637f767c..0186684e 100644 --- a/test/servicesSpec.js +++ b/test/servicesSpec.js @@ -523,14 +523,14 @@ describe("service", function(){ expect(onChangeSpy.callCount).toBe(1); }); - - it('should interpolate route variables in the redirected path from hashPath', function() { + it('should interpolate route variables in the redirected hashPath from the original hashPath', + function() { var scope = angular.scope(), $location = scope.$service('$location'), $browser = scope.$service('$browser'), $route = scope.$service('$route'); - $route.when('/foo/:id/foo/:subid/:ignoredId', {redirectTo: '/bar/:id/:subid/23'}); + $route.when('/foo/:id/foo/:subid/:extraId', {redirectTo: '/bar/:id/:subid/23'}); $route.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); scope.$eval(); @@ -538,27 +538,54 @@ describe("service", function(){ scope.$eval(); //triggers initial route change - match the redirect route $browser.defer.flush(); //triger route change - match the route we redirected to - expect($location.hash).toBe('/bar/id1/subid3/23'); + expect($location.hash).toBe('/bar/id1/subid3/23?extraId=gah'); expect($route.current.template).toBe('bar.html'); }); - it('should interpolate route variables in the redirected path from hashSearch', function() { + it('should interpolate route variables in the redirected hashPath from the original hashSearch', + function() { var scope = angular.scope(), $location = scope.$service('$location'), $browser = scope.$service('$browser'), $route = scope.$service('$route'); $route.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); - $route.when('/foo/:id', {redirectTo: '/bar/:id/:subid/99'}); + $route.when('/foo/:id/:extra', {redirectTo: '/bar/:id/:subid/99'}); scope.$eval(); - $location.hash = '/foo/id3?subid=sid1&ignored=true'; + $location.hash = '/foo/id3/eId?subid=sid1&appended=true'; scope.$eval(); //triggers initial route change - match the redirect route $browser.defer.flush(); //triger route change - match the route we redirected to - expect($location.hash).toBe('/bar/id3/sid1/99'); + expect($location.hash).toBe('/bar/id3/sid1/99?appended=true&extra=eId'); expect($route.current.template).toBe('bar.html'); }); + + it('should allow custom redirectTo function to be used', function() { + var scope = angular.scope(), + $location = scope.$service('$location'), + $browser = scope.$service('$browser'), + $route = scope.$service('$route'); + + $route.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); + $route.when('/foo/:id', + {redirectTo: customRedirectFn}); + scope.$eval(); + + $location.hash = '/foo/id3?subid=sid1&appended=true'; + scope.$eval(); //triggers initial route change - match the redirect route + $browser.defer.flush(); //triger route change - match the route we redirected to + + expect($location.hash).toBe('custom'); + + function customRedirectFn(routePathParams, hash, hashPath, hashSearch) { + expect(routePathParams).toEqual({id: 'id3'}); + expect(hash).toEqual($location.hash); + expect(hashPath).toEqual($location.hashPath); + expect(hashSearch).toEqual($location.hashSearch); + return 'custom'; + } + }); }); -- cgit v1.2.3