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