Skip to content

Commit

Permalink
feat(ngRoute): cancel $routeChangeStart via $event.preventDefault()
Browse files Browse the repository at this point in the history
This change allows ngRoute route changes to be cancelled using $event.preventDefault.

This enables route changes to be aborted at the discretion of the application.

Route changes may not be cancelled if forceReload is set to true.

Closes angular#5581
  • Loading branch information
caitp committed Jan 9, 2014
1 parent 28fc80b commit b3b46fb
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
29 changes: 28 additions & 1 deletion src/ngRoute/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -494,8 +514,15 @@ function $RouteProvider(){
angular.copy(last.params, $routeParams);
$rootScope.$broadcast('$routeUpdate', last);
} else if (next || last) {
var wasForceReload = forceReload;
forceReload = false;
$rootScope.$broadcast('$routeChangeStart', next, last);

if ($rootScope.$broadcast('$routeChangeStart', next, last).defaultPrevented &&
!wasForceReload) {
$rootScope.$broadcast('$routeChangeCancelled', next, last);
return;
}

$route.current = next;
if (next) {
if (next.redirectTo) {
Expand Down
55 changes: 55 additions & 0 deletions test/ngRoute/routeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,61 @@ 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) {
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();
});
});


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();
});
});
});


Expand Down

0 comments on commit b3b46fb

Please sign in to comment.