diff options
| -rw-r--r-- | src/service/route.js | 29 | ||||
| -rw-r--r-- | test/service/routeSpec.js | 136 |
2 files changed, 162 insertions, 3 deletions
diff --git a/src/service/route.js b/src/service/route.js index 3d555e4d..2634eb6c 100644 --- a/src/service/route.js +++ b/src/service/route.js @@ -68,6 +68,8 @@ angularServiceInject('$route', function(location, $updateView) { matcher = switchRouteMatcher, parentScope = this, dirty = 0, + lastHashPath, + lastRouteParams, $route = { routes: routes, @@ -136,6 +138,18 @@ angularServiceInject('$route', function(location, $updateView) { * 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.myHashSearchParam; + * }, function(params) { + * //do stuff with params + * }); + * } + * * @returns {Object} route object * * @description @@ -144,8 +158,8 @@ angularServiceInject('$route', function(location, $updateView) { 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,6 +223,14 @@ angularServiceInject('$route', function(location, $updateView) { function updateRoute(){ var childScope, routeParams, pathParams, segmentMatch, key, redir; + if ($route.current) { + if (!$route.current.reloadOnSearch && (lastHashPath == location.hashPath)) { + $route.current.params = extend({}, location.hashSearch, lastRouteParams); + return; + } + } + + lastHashPath = location.hashPath; $route.current = null; forEach(routes, function(rParams, rPath) { if (!pathParams) { @@ -255,6 +277,7 @@ angularServiceInject('$route', function(location, $updateView) { scope: childScope, params: extend({}, location.hashSearch, pathParams) }); + lastRouteParams = pathParams; } //fire onChange callbacks @@ -266,7 +289,7 @@ angularServiceInject('$route', function(location, $updateView) { } - this.$watch(function(){return dirty + location.hash;}, updateRoute); + this.$watch(function(){ return dirty + location.hash; }, updateRoute); return $route; }, ['$location', '$updateView']); diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js index fc2c7f9d..4d24279c 100644 --- a/test/service/routeSpec.js +++ b/test/service/routeSpec.js @@ -227,4 +227,140 @@ 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.$eval(); + expect(reloaded).toHaveBeenCalled(); + reloaded.reset(); + + // trigger reload + $location.hashSearch.foo = 'bar'; + scope.$eval(); + 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.$eval(); + expect(reloaded).toHaveBeenCalled(); + reloaded.reset(); + + // don't trigger reload + $location.hashSearch.foo = 'bar'; + scope.$eval(); + 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.$eval(); + expect(reloaded).toHaveBeenCalled(); + expect(onRouteChange).toHaveBeenCalled(); + reloaded.reset(); + onRouteChange.reset(); + + $location.updateHash('/foo/bbb'); + scope.$eval(); + expect(reloaded).toHaveBeenCalled(); + expect(onRouteChange).toHaveBeenCalled(); + reloaded.reset(); + onRouteChange.reset(); + + $location.hashSearch.foo = 'bar'; + scope.$eval(); + 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(params) { + routeParams(params); + }); + } + + expect(routeParams).not.toHaveBeenCalled(); + + $location.updateHash('/foo'); + scope.$eval(); + expect(routeParams).toHaveBeenCalledWith({}); + routeParams.reset(); + + // trigger reload + $location.hashSearch.foo = 'bar'; + scope.$eval(); + expect(routeParams).toHaveBeenCalledWith({foo: 'bar'}); + routeParams.reset(); + + $location.updateHash('/bar/123'); + scope.$eval(); + expect(routeParams).toHaveBeenCalledWith({barId: '123'}); + routeParams.reset(); + + // don't trigger reload + $location.hashSearch.foo = 'bar'; + scope.$eval(); + $route.current.scope.$eval(); // ng:view propagates evals so we have to do it by hand here + expect(routeParams).toHaveBeenCalledWith({barId: '123', foo: 'bar'}); + }); + }); }); |
