Angular route resolvers and controller activation. Two great options for running logic on entrance of a new View or route. I get a lot of questions about which technique to use.
I'm using AngularJS and I see 2 common patterns to retrieve data and run logic when transitioning to a new View. What's the difference between running code when a controller starts and running code in a route resolver?
The key is that both are valid options. And in some cases either is fine, while in others you want to pick one over the other. They path to choosing begins with understanding the differences. The biggest difference between the 2 for a user is that resolvers happen before the route and activate happens after the route.
Code
Let’s start by looking at the difference in the code between the two options.
Controller Activate
This first example shows running code on controller activation. I name the function activate
by convention. This example is pulled directly from my Angular style guide here Y080.
// avengers.js
function Avengers(dataservice) {
var vm = this;
vm.avengers = [];
vm.title = 'Avengers';
activate();
function activate() {
return dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
}
Route Resolve
This second code example shows running code on before a route executes. This example is pulled directly from my Angular style guide here Y081. This demonstrates using ngRoute but the same idea works with ui-router.
// route-config.js
angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm',
resolve: {
moviesPrepService: moviesPrepService
}
});
}
function moviesPrepService(movieService) {
return movieService.getMovies();
}
// avengers.js
angular
.module('app')
.controller('Avengers', Avengers);
Avengers.$inject = ['moviesPrepService'];
function Avengers(moviesPrepService) {
var vm = this;
vm.movies = moviesPrepService.movies;
}
Behavior
Now let’s examine some of the ways they behave differently.
Controller Activate
- The code executes after the route and in the controller's
activate
function - The View starts to load right away
- Data binding kicks in when the
activate
promise resolves - A “busy” animation can be shown during the view transition (via
ng-view
orui-view
)
Route Resolve
- The code executes before the route via a promise
- Rejecting the promise cancels the route
- Resolve makes the new view wait for the route to resolve
- A “busy” animation can be shown before the resolve and through the view transition
I use a route resolve when I want to decide to cancel the route before ever transitioning to the View.
When I need to get data for a controller I use the controller’s activate
function. The controller activate makes it convenient to re-use the logic for a refresh for the controller/View, keeps the logic together, gets the user to the View faster, makes animations easy on the ng-view
or ui-view
, and feels snappier to the user. I find this to be the more common scenario, but both are valid depending on how the set of behavior fits your situation.