Lifecycle hooks let you control each stage of a route navigation.
There are four main lifecycle hooks: canActivate
, activate
, and canDeactivate
, and deactivate
.
A component can make use of these hooks by having its controller implement any number or combination of them.
To understand how this works, let's step through a simple case where a component wants to navigate from one route to another.
Before a component can fire any lifecycle hooks, Angular needs to instantiate it. In this phase of routing, Angular injects the controller's dependencies.
If the controller can't be instantiated (the constructor throws), the router cancels navigation. However, you should avoid control flow logic by means of throwing exceptions. If you have logic that determines whether or not to perform a navigation, use thecanActivate
hook instead.
Constructors should be lightweight.
If you need to do a lot of work to setup a controller, consider using the activate
lifecycle hook.
Before switching to a new component, this hook runs for each active component in the app.
If any of them return false
, a rejected promise, or a promise that resolves to false
,
the navigation is cancelled.
This hook is useful for authentication.
angular.module('app', [])
.controller('MyController', ['user', '$http', MyController]);
function MyController(user, $http) {
this.user = user;
this.$http = $http;
}
MyController.prototype.canActivate = function() {
return this.user.isAdmin;
};
This hook fires just before the nagivation finishes.
This hook is useful for cases where you want your component to do some intensive work.
angular.module('app', [])
.controller('MyController', ['user', '$http', MyController]);
function MyController(user, $http) {
this.user = user;
this.$http = $http;
}
MyController.prototype.canActivate = function() {
return this.user.isAdmin;
};
MyController.prototype.activate = function() {
return this.bigFiles = this.$http.downloadBigFiles();
};
This hook fires for each component that is removed as part of navigation.
canDeactivate
fires before any new components are instantiated.
If any of them return false
, a rejected promise, or a promise that resolves to false
,
the navigation is cancelled.
canDeactivate
is useful for making sure that data is properly persisted before navigating away.
In this example, we show a dialog asking a user whether or not to save their work before continuing.
angular.module('app.save', [])
.controller('SaveController', ['$q', SaveController]);
function SaveController($q) {
this.$q = $q;
}
/*
* return a promise that is resolved based on the user's
* choice in a dialog box
*/
SaveController.prototype.canDeactivate = function() {
this.deferred = this.$q.defer();
this.showSaveDialog = true;
return this.deferred.promise();
};
<div>
<div ng-show="showSaveDialog">
<p>Would you like to save your work?</p>
<button ng-click="save.deferred.resolve()">Save</button>
<button ng-click="save.deferred.reject()">Discard</button>
</div>
</div>
This hook fires for each component that is removed as part of navigation.
deactivate
is useful for doing cleanup work.
This hook fires after the canActivate
of the new component and canDeactivate
of the component to be removed, but before activate
of the new component.
In this example, we have a component that prevents navigation until a user saves
angular.module('app.my', [])
.controller('MyController', ['user', '$http', MyController]);
function MyController(user, $http) {
this.user = user;
this.$http = $http;
this.userDataPersisted = true;
}
MyController.prototype.updateUserName = function(newName) {
var self = this;
this.userDataPersisted = false;
return this.user.setName(newName).then(function () {
self.userDataPersisted = true;
});
};
MyController.prototype.canActivate = function() {
return this.user.isAdmin;
};
MyController.prototype.activate = function() {
this.user.downloadBigFiles();
};
MyController.prototype.canDeactivate = function() {
return this.userDataPersisted;
};
This is the basic logic that the router uses when determining whether or not to perform a navigation.