Skip to content

Commit 80ed319

Browse files
committed
feat(ngRoute): allow cancelling $route updates via $routeChangeEvent
Previously, one could perform this feat by listening to both $locationChangeStart as well as $routeChangeStart, and being careful to update the route correctly. Now, it's possible to simply preventDefault() on the $beforeRouteChange event in order to prevent location and route from being updated. While this does not cancel $routeChangeStart, it does ensure that the correct location is restored, and provides the same information as $routeChangeStart. Closes angular#5855 Closes angular#5714 Closes angular#5581
1 parent cad9560 commit 80ed319

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/ngRoute/route.js

+28
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,21 @@ function $RouteProvider(){
364364
* </example>
365365
*/
366366

367+
/**
368+
* @ngdoc event
369+
* @name $route#$beforeRouteChange
370+
* @eventType broadcast on root scope
371+
*
372+
* @description
373+
* Broadcasted during locationChangeStart, will cancel $locationChangeStart
374+
* if preventDefault() is called, thus preventing subsequent $routeChange
375+
* events.
376+
*
377+
* @param {Object} angularEvent Synthetic event object.
378+
* @param {Route} nextRoute route information of the future route.
379+
* @param {Route} currentRoute current route information.
380+
*/
381+
367382
/**
368383
* @ngdoc event
369384
* @name $route#$routeChangeStart
@@ -469,6 +484,7 @@ function $RouteProvider(){
469484
}
470485
};
471486

487+
$rootScope.$on('$locationChangeStart', beforeUpdateRoute);
472488
$rootScope.$on('$locationChangeSuccess', updateRoute);
473489

474490
return $route;
@@ -582,6 +598,18 @@ function $RouteProvider(){
582598
}
583599

584600

601+
// $locationChangeStart handler. Dispatches $beforeRouteChange, and cancels $locationChangeStart
602+
// if the user cancels the $beforeRouteChange event.
603+
function beforeUpdateRoute(event, next, current) {
604+
var nextRoute = parseRoute();
605+
var lastRoute = $route.current;
606+
607+
if ($rootScope.$broadcast('$beforeRouteChange', nextRoute, lastRoute).defaultPrevented) {
608+
event.preventDefault();
609+
}
610+
}
611+
612+
585613
/**
586614
* @returns {Object} the current active route, by matching it against the URL
587615
*/

test/ngRoute/routeSpec.js

+59
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,65 @@ describe('$route', function() {
741741
expect($exceptionHandler.errors).toEqual([myError]);
742742
});
743743
});
744+
745+
746+
it('should pass nextRoute and currentRoute to $beforeRouteChange', function() {
747+
module(function($routeProvider) {
748+
$routeProvider.when('/a', {
749+
template: '<p>route A</p>'
750+
}).when('/b', {
751+
template: '<p>route B</p>'
752+
});
753+
});
754+
755+
inject(function($location, $route, $rootScope) {
756+
var beforeRouteChangeCalled = false;
757+
$location.path('/a');
758+
$rootScope.$digest();
759+
760+
$rootScope.$on('$beforeRouteChange', function(event, nextRoute, currentRoute) {
761+
beforeRouteChangeCalled = true;
762+
expect(nextRoute.template).toBe('<p>route B</p>');
763+
expect(currentRoute.template).toBe('<p>route A</p>');
764+
});
765+
766+
$location.path('/b');
767+
$rootScope.$digest();
768+
769+
expect(beforeRouteChangeCalled).toBe(true);
770+
});
771+
});
772+
773+
774+
it('should cancel $locationChange when $beforeRouteChange is cancelled', function() {
775+
module(function($routeProvider) {
776+
$routeProvider.when('/a', {
777+
template: '<p>route A</p>'
778+
}).when('/b', {
779+
template: '<p>route B</p>'
780+
});
781+
});
782+
783+
inject(function($location, $route, $rootScope) {
784+
var didChangeLocation = false;
785+
$location.path('/a');
786+
$rootScope.$digest();
787+
788+
$rootScope.$on('$beforeRouteChange', function(event, nextRoute, currentRoute) {
789+
event.preventDefault();
790+
});
791+
$rootScope.$on('$locationChangeSuccess', function() {
792+
didChangeLocation = true;
793+
});
794+
795+
$location.path('/b');
796+
$rootScope.$digest();
797+
798+
expect(didChangeLocation).toBe(false);
799+
expect($location.path()).toBe('/a');
800+
expect($route.current.template).toBe('<p>route A</p>');
801+
});
802+
});
744803
});
745804

746805

0 commit comments

Comments
 (0)