One of the biggest values I get from working on side projects is the unexpected discoveries made that can be applied to my full-time job. This is one of the reasons I've stopped caring so much about "completing" these projects and instead have focused on simply enjoying the process of working on them.
One of these discoveries came a few months ago while reading through the documentation on the wonderful UI-Router framework for Angular. It turns out you can define any number of properties to "resolve" when loading a route. Here's a brief example:
$stateProvider.state('contacts', {
url: '/contacts',
resolve: {
'contacts': function ($http) {
return $http({
method: 'GET',
url: '/api/contacts'
});
}
},
controller: function (contacts) {
scope.contacts = contacts;
},
template: '<ul ng-repeat="contact in contacts">' +
'<li>{{contact.name}}</li>' +
'</ul>'
});
If you're familiar with routing in Angular, you'll recognize the url
, controller
and template
properties of our route definition. If you're extra familiar with routing in Angular, you'll recognize the resolve
property as well, in which case I have to wonder why you're still reading this.
However, if you're like me, the resolve
property is a curiousity. Something you're not sure whether you like or not, but you're intrigued by it. The basics of it is that you're injecting data into your controller from the route definition.
Why is this pretty awesome? Well, for many months I spent most of my time writing controllers that, when instantiated, displayed a loading message, made an API call, then hid the message and displayed the data. A lot of boilerplate code for very standard functionality.
With resolve, it kind of takes care of this for you (although no loading message is displayed). Instead of loading the route then loading the data, it waits for the data to load before instantiating the controller. This includes waiting for any async calls to complete.
That means you can, as shown in the example above, return a promise from your resolve property function, and the result of that promise will be injected into your controller.
The main benefit of all of this is a much cleaner controller. You're no longer cluttering it up with model specific logic just to load the data. You can also do some nifty stuff with inheriting resolved data from parent states, which means DRYer code throughout your app.
I'm refraining from getting into technical specifics, mainly because I'd be copying/pasting from the UI-router docs. There is a lot of great documentation already in written for the functionality.
It is worth mentioning that if you're not using UI-Router (you should be), ngRoute also supports resolve
. The functionality isn't as verbose as what UI-Router provides (did I mention you should be using UI-Router?), but it does handle promises, which is normally what you need resolve
for.
There are some drawbacks to all of this. Route definitions get a little more cluttered, you still have to handle when data fails to load, and the page won't display anything until all the data has loaded (so no loading messages, which some might say is a good thing). But overall, I think those are issues that can be solved in other ways, while still keeping the benefits that resolve
provides.