add support for hashSearch redirection and custom redirection functions

This commit is contained in:
Igor Minar 2011-02-07 14:32:28 -08:00
parent 8724e97b7e
commit 86321d1f57
2 changed files with 75 additions and 27 deletions

View file

@ -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.<string>}` - 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;
}

View file

@ -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';
}
});
});