diff options
| -rw-r--r-- | src/service/route.js | 36 | ||||
| -rw-r--r-- | test/service/routeSpec.js | 135 |
2 files changed, 165 insertions, 6 deletions
diff --git a/src/service/route.js b/src/service/route.js index 972d616e..b7e4814b 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -68,6 +68,8 @@ angularServiceInject('$route', function($location) { matcher = switchRouteMatcher, parentScope = this, dirty = 0, + lastHashPath, + lastRouteParams, $route = { routes: routes, @@ -136,6 +138,18 @@ angularServiceInject('$route', function($location) { * The custom `redirectTo` function is expected to return a string which will be used * to update `$location.hash`. * + * - `[reloadOnSearch=true]` - {boolean=} - reload route when $location.hashSearch + * changes. If this option is disabled, you should set up a $watch to be notified of + * param (hashSearch) changes as follows: + * + * function MyCtrl($route) { + * this.$watch(function() { + * return $route.current.params; + * }, function(scope, params) { + * //do stuff with params + * }); + * } + * * @returns {Object} route object * * @description @@ -144,8 +158,8 @@ angularServiceInject('$route', function($location) { when:function (path, params) { if (isUndefined(path)) return routes; //TODO(im): remove - not needed! var route = routes[path]; - if (!route) route = routes[path] = {}; - if (params) extend(route, params); + if (!route) route = routes[path] = {reloadOnSearch: true}; + if (params) extend(route, params); //TODO(im): what the heck? merge two route definitions? dirty++; return route; }, @@ -209,9 +223,18 @@ angularServiceInject('$route', function($location) { function updateRoute(){ var selectedRoute, pathParams, segmentMatch, key, redir; - if ($route.current && $route.current.scope) { - $route.current.scope.$destroy(); + if ($route.current) { + if (!$route.current.reloadOnSearch && (lastHashPath == $location.hashPath)) { + $route.current.params = extend($location.hashSearch, lastRouteParams); + return; + } + + if ($route.current.scope) { + $route.current.scope.$destroy(); + } } + + lastHashPath = $location.hashPath; $route.current = null; // Match a route forEach(routes, function(rParams, rPath) { @@ -255,19 +278,20 @@ angularServiceInject('$route', function($location) { $route.current = extend({}, selectedRoute); $route.current.params = extend({}, $location.hashSearch, pathParams); + lastRouteParams = pathParams; } //fire onChange callbacks forEach(onChange, parentScope.$eval, parentScope); - // Create the scope if we have mtched a route + // Create the scope if we have matched a route if ($route.current) { $route.current.scope = parentScope.$new($route.current.controller); } } - this.$watch(function(){return dirty + $location.hash;}, updateRoute); + this.$watch(function(){ return dirty + $location.hash; }, updateRoute); return $route; }, ['$location']); diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js index bfe201d1..72c7745c 100644 --- a/test/service/routeSpec.js +++ b/test/service/routeSpec.js @@ -260,4 +260,139 @@ describe('$route', function() { } }); }); + + + describe('reloadOnSearch', function() { + it('should reload a route when reloadOnSearch is enabled and hashSearch changes', function() { + var scope = angular.scope(), + $location = scope.$service('$location'), + $route = scope.$service('$route'), + reloaded = jasmine.createSpy('route reload'); + + $route.when('/foo', {controller: FooCtrl}); + $route.onChange(reloaded); + + function FooCtrl() { + reloaded(); + } + + $location.updateHash('/foo'); + scope.$digest(); + expect(reloaded).toHaveBeenCalled(); + reloaded.reset(); + + // trigger reload + $location.hashSearch.foo = 'bar'; + scope.$digest(); + expect(reloaded).toHaveBeenCalled(); + }); + + + it('should not reload a route when reloadOnSearch is disabled and only hashSearch changes', + function() { + var scope = angular.scope(), + $location = scope.$service('$location'), + $route = scope.$service('$route'), + reloaded = jasmine.createSpy('route reload'); + + $route.when('/foo', {controller: FooCtrl, reloadOnSearch: false}); + $route.onChange(reloaded); + + function FooCtrl() { + reloaded(); + } + + expect(reloaded).not.toHaveBeenCalled(); + + $location.updateHash('/foo'); + scope.$digest(); + expect(reloaded).toHaveBeenCalled(); + reloaded.reset(); + + // don't trigger reload + $location.hashSearch.foo = 'bar'; + scope.$digest(); + expect(reloaded).not.toHaveBeenCalled(); + }); + + + it('should reload reloadOnSearch route when url differs only in route path param', function() { + var scope = angular.scope(), + $location = scope.$service('$location'), + $route = scope.$service('$route'), + reloaded = jasmine.createSpy('routeReload'), + onRouteChange = jasmine.createSpy('onRouteChange'); + + $route.when('/foo/:fooId', {controller: FooCtrl, reloadOnSearch: false}); + $route.onChange(onRouteChange); + + function FooCtrl() { + reloaded(); + } + + expect(reloaded).not.toHaveBeenCalled(); + expect(onRouteChange).not.toHaveBeenCalled(); + + $location.updateHash('/foo/aaa'); + scope.$digest(); + expect(reloaded).toHaveBeenCalled(); + expect(onRouteChange).toHaveBeenCalled(); + reloaded.reset(); + onRouteChange.reset(); + + $location.updateHash('/foo/bbb'); + scope.$digest(); + expect(reloaded).toHaveBeenCalled(); + expect(onRouteChange).toHaveBeenCalled(); + reloaded.reset(); + onRouteChange.reset(); + + $location.hashSearch.foo = 'bar'; + scope.$digest(); + expect(reloaded).not.toHaveBeenCalled(); + expect(onRouteChange).not.toHaveBeenCalled(); + }); + + + it('should update route params when reloadOnSearch is disabled and hashSearch', function() { + var scope = angular.scope(), + $location = scope.$service('$location'), + $route = scope.$service('$route'), + routeParams = jasmine.createSpy('routeParams'); + + $route.when('/foo', {controller: FooCtrl}); + $route.when('/bar/:barId', {controller: FooCtrl, reloadOnSearch: false}); + + function FooCtrl() { + this.$watch(function() { + return $route.current.params; + }, function(scope, value) { + routeParams(value); + }); + } + + expect(routeParams).not.toHaveBeenCalled(); + + $location.updateHash('/foo'); + scope.$digest(); + expect(routeParams).toHaveBeenCalledWith({}); + routeParams.reset(); + + // trigger reload + $location.hashSearch.foo = 'bar'; + scope.$digest(); + expect(routeParams).toHaveBeenCalledWith({foo: 'bar'}); + routeParams.reset(); + + $location.updateHash('/bar/123'); + scope.$digest(); + expect(routeParams).toHaveBeenCalledWith({barId: '123'}); + routeParams.reset(); + + // don't trigger reload + $location.hashSearch.foo = 'bar'; + scope.$digest(); + expect(routeParams).toHaveBeenCalledWith({barId: '123', foo: 'bar'}); + }); + }); }); |
