It’s sometimes useful to be able to preload or resolve data previous to an Angular view being displayed. Such was the case recently for our current user object. It simplified a lot of things in the app to have the guarantee of a loaded current user previous to displaying pages. The Angular router has a great mechanism built in to do just this sort of thing, called
For the example, our current user object is super simple. Just pretend that it holds all of the relevant details of a user. These details are useful for displaying various things in the app that need the context of who the currently logged-in user is.
1 2 3 4 5 6 7 8
Note that for our app there is just one
CurrentUser object, a singleton, because we return a single instance from our factory, not a class.
The Angular router is used for client-side routing of urls. Our angular app is called
app. We setup some angular submodules to hold config, services, and controllers.
Let’s say that we have a home page and a profile page for our example.
Each route can be configured with a
resolve object. The key of that object is the name of a local variable and the value is a function which returns a promise. The resolution value of the promise is the data you want before the route executes.After all the promises are resolved, the route is free to switch and execute. Until then, each unresolved promise will block the route from executing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
run method is essentially the Angular app’s main method, starting the program. I want to ensure the current user is loaded for each route. In this case, instead of putting a
resolve config on each route, I’m looping through all routes after their initial definition and adding the
CurrentUser: resolves.getCurrentUser config.
In our resolve function we setup our own promise via the
$q service. We check to see if our singleton
CurrentUser is already loaded. If it’s not, we fetch it. If it has been fetched once already, we resolve the promise with the value that’s already available.
1 2 3 4 5 6 7 8 9 10 11 12 13
Now that we have the
CurrentUser guaranteed to be resolved (fetched and returned) by the time we enter all routes, we need to grab the value of
CurrentUser and put it in
$scope where our program would normally pick up and start using variables.
1 2 3 4 5
We listen the Angular-provided event when a route is successfully entered:
$routeChangeSuccess. The value we care about is available on the
locals object, placed there magically by the resolve function.
When to Use
There are a few bits to piece together to make this happen. It might be simpler than other solutions or make more sense for you in your app if you need something(s) loaded previous to executing on a route.
I would definitely use this feature judiciously, as it seems to eat away at one of the advantages of a client-side app in the first place: asynchronous loading. We’8re blocking the whole app from going forward when we’re in the process of resolving. That boundary used to be on the edge of the server, building up the page before it was servable to the client. Now, on a web client, we have multiple requests that can happen in parallel and we can render bits as they’re available – important bits first and so on.