diff --git a/src/ngRoute/route.js b/src/ngRoute/route.js index 2db74a02495d..bd927ea59ec5 100644 --- a/src/ngRoute/route.js +++ b/src/ngRoute/route.js @@ -375,11 +375,31 @@ function $RouteProvider(){ * defined in `resolve` route property. Once all of the dependencies are resolved * `$routeChangeSuccess` is fired. * + * The route change may be cancelled with angularEvent.preventDefault(), which will + * in turn trigger a {@link ngRoute.$route#events_$routeChangeCancelled $routeChangeCancelled} + * event. + * * @param {Object} angularEvent Synthetic event object. * @param {Route} next Future route information. * @param {Route} current Current route information. */ + /** + * @ngdoc event + * @name ngRoute.$route#$routeChangeCancelled + * @eventOf ngRoute.$route + * @eventType broadcast on root scope + * @description + * Broadcasted after a route has been cancelled during + * {@link ngRoute.$route#events_$routeChangeStart $routeChangStart}, using the + * angularEvent.preventDefault() method. This method enables applications to prevent + * a route change from occurring without any additional work. + * + * @param {Object} angularEvent Synthetic event object. + * @param {Route} cancelled The cancelled route information. + * @param {Route} current Current route information. + */ + /** * @ngdoc event * @name ngRoute.$route#$routeChangeSuccess @@ -484,7 +504,7 @@ function $RouteProvider(){ return params; } - function updateRoute() { + function updateRoute($event, newUrl, oldUrl) { var next = parseRoute(), last = $route.current; @@ -495,8 +515,13 @@ function $RouteProvider(){ angular.copy(last.params, $routeParams); $rootScope.$broadcast('$routeUpdate', last); } else if (next || last) { + if ($rootScope.$broadcast('$routeChangeStart', next, last).defaultPrevented && + !forceReload) { + $location.$$parse($location.$$rewrite(oldUrl)); + $rootScope.$broadcast('$routeChangeCancelled', next, last); + return; + } forceReload = false; - $rootScope.$broadcast('$routeChangeStart', next, last); $route.current = next; if (next) { if (next.redirectTo) { diff --git a/test/ngRoute/routeSpec.js b/test/ngRoute/routeSpec.js index 52484116d508..d222008efdd2 100644 --- a/test/ngRoute/routeSpec.js +++ b/test/ngRoute/routeSpec.js @@ -723,6 +723,62 @@ describe('$route', function() { expect($exceptionHandler.errors).toEqual([myError]); }); }); + + + it('should broadcast $routeChangeCancelled if $routeChangeSuccess.defaultPrevented', function() { + module(function($routeProvider) { + $routeProvider.when('/r1', { + templateUrl: 'r1.html' + }); + }); + inject(function($route, $httpBackend, $location, $rootScope, $browser) { + var success = jasmine.createSpy('$routeChangeSuccess'), + error = jasmine.createSpy('$routeChangeError'), + cancelled = jasmine.createSpy('$routeChangeCancelled'); + $rootScope.$on('$routeChangeStart', function($event) { $event.preventDefault(); }); + $rootScope.$on('$routeChangeSuccess', success); + $rootScope.$on('$routeChangeError', error); + $rootScope.$on('$routeChangeCancelled', cancelled); + + $location.path('/r1'); + $rootScope.$digest(); + + expect(success).not.toHaveBeenCalled(); + expect(error).not.toHaveBeenCalled(); + expect(cancelled).toHaveBeenCalled(); + expect($location.absUrl()).toBe('http://server/'); + }); + }); + + + it('should not broadcast $routeChangeCancelled if force-reloading', function() { + module(function($routeProvider) { + $routeProvider.when('/r1', { + templateUrl: 'foo.html' + }); + }); + inject(function($route, $httpBackend, $location, $rootScope) { + var success = jasmine.createSpy('$routeChangeSuccess'), + error = jasmine.createSpy('$routeChangeError'), + cancelled = jasmine.createSpy('$routeChangeCancelled'); + + $location.path('/r1'); + $rootScope.$digest(); + $httpBackend.flush(); + + $rootScope.$on('$routeChangeStart', function($event) { $event.preventDefault(); }); + $rootScope.$on('$routeChangeSuccess', success); + $rootScope.$on('$routeChangeError', error); + $rootScope.$on('$routeChangeCancelled', cancelled); + + $route.reload(); + $rootScope.$digest(); + + expect(cancelled).not.toHaveBeenCalled(); + expect(error).not.toHaveBeenCalled(); + expect(success).toHaveBeenCalled(); + }); + }); });