I was reading the docs of ui-router but I couldn't grasp the concept of resolves for controllers in each state. I am not able to figure out where should we use resolve and why the controller attached to a state is not enough (as we can inject any dependencies in it we want) ?
I've tried going through docs and other tutorials several times but its quite confusing , Can someone please explain it with its real life application?
3 Answers
Imagine you want to create a modal and pass some data to it. I'm using the angular-ui-bootstrap modals for this example.
var openExampleModal = function () { var modalInstance = $modal.open({ templateUrl: "Modal.html", controller: "ModalController", size: "lg" }); return modalInstance.result; }; Now if you want to pass some data to this modal on initialization, you can either save it in your $rootScope or some data service, or you can use resolve to inject it into your controller directly without having to use anything else.
var openExampleModal = function (myData) { var modalInstance = $modal.open({ templateUrl: "Modal.html", controller: "ModalController", size: "lg", resolve: { sampleData: function () { return myData; } } }); return modalInstance.result; }; and in your controller you would have:
MyController.$inject = ["sampleData"]; function Mycontroller(sampleData) { //You can access the data you passed on via sampleData variable now. }; Resolve is used to inject your own custom objects into the controller, not for injecting dependencies.
Comments
A resolve is simply a value that is passed to the controller upon instantiation (which are used like an injected value). The neat thing about them is that if the value returned is a promise, the view/controller won't load until the promise has resolved.
The way you use them is by adding a resolve key to your route state, and returning the object you want injected into your controller (also naming it). For example:
.state('example', { url: '/page', templateUrl: 'sometemplate.html', controller: 'SomeCtrl', resolve: { injectionName: function(){ // return a value or promise here to be injected as injectionName into your controller } } }); Then inside your controller you simply add the resolve name to the controller injected values:
.controller('SomeCtrl', function($scope, injectionName){ // do stuff with injectionName }); Just note that if you do return a promise, the value that is injected is the result of the promise (not the promise itself). Also note that if the promise errors the view/controller will not load, and an error will be thrown. As @koox00 commented, this error will fail silently unless $stateChangeErrorError is handled (usually in your apps primary run() function).
So why would you use this? Well if not inferred from above, you do this usually when you want your view/controller to wait until some async process has completed before loading a particular state. This saves you from creating loaders or loading processes for every single view/controller, moving it to a simple definition of what needs to be loaded.
1 Comment
$stateChangeError eventAs said by Jean-Philippe you can use resolve if you want to load some data before switching to a certain state. Resolve waits and blocks until the data is arrived and only then the state transition is done. It is an highly discussed topic whether using a resolve or loading the data on the fly within the controller. I would say: It depends on your use case :)
Further info from supercool todd motto: https://toddmotto.com/resolve-promises-in-angular-routes/