background

AngularJS was founded in 2009 by Misko Hevery and others before being acquired by Google. Is an excellent front-end JS framework, has been used in a number of Google products.

I recently worked on a front-end project using the same framework, where there was a lot of code to use the Resolve configuration during routing. It took me a few days to figure out what it does and how it flows.

Reslove configuration items

Resolve is a key-value in the state configuration parameter. Each value is a dependency injectable function and returns an object.

The methods in the configuration item are executed before the Controller Controller is instantiated. Let’s look at two common scenarios for using Resolve.

AngularJS routing syntax

Simple AngularJS page navigation requires the $stateProvider route configuration, and resolve can be used if you need to dynamically add the controller that the routing page depends on, or if some controller instantiation parameters need to be injected.

First, let’s look at the use of dynamically loaded dependencies. The route configuration in index.html on demo’s home page is as follows:

"use strict"; // $stateProvider. State resolve: Define (['admin-app'], function (adminApp) {console.log(' load adminapprouter.js '); /* Define admin app route */ adminApp.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, {$urlRouterProvider). The console log (' adminAppRouter... routing configuration); / / the routing configuration $urlRouterProvider. Otherwise ('/myhome '); // if (uI-sref = state) {// if (uI-sref = state) { For example :/viewshome? Id&name &age //3, templateUrl, the page to load corresponding to the request URL //4, resolve, which uses the $q service for lazy loading, returns a Promise object, $stateProvider. State (' myHome ',{url: '/ myHome ', templateUrl: 'page/my_home.tpl.html', controller: 'MyHomeController', controllerAs: 'ctrl', resolve: {// To add a dynamic dependency, you need to provide an object that returns a promise. This should be the general logic. ['$q', '$rootScope', function($q, $rootScope) {console.log("resolve loadJs define.") var defer = $q.defer(); // Call the defined viewshomecontroller.js module console.log('adminAppRouter... Resolve start.');  require(['viewsHome-controller'], $rootScope.$apply(function() {console.log('scope apply resolve start ') {console.log('scope apply resolve start ') .'); defer.resolve(); console.log('scope apply resolve end .'); }); Defer.resolve (); // Even if you comment out the apply above, placing it in the asynchronous callback will render the page correctly. Console. log('adminAppRouter... routing configuration viewshOMe-Controller function');}); // defer.resolve(); Controller method does not define console.log('adminAppRouter... Route configuration resolve Finish.'); return deferred. Promise;  }] } }) .state('otherHome',{ url: '/otherHome', templateUrl: 'views/other_home.html', controller: 'OtherHomeController', resolve: { load: ['$q', '$rootScope', function($q, $rootScope) { var defer = $q.defer();  require(['other-controller'], function() { $rootScope.$apply(function() { defer.resolve(); }); });  return defer.promise; }] } }) } ]) })Copy the code

Focus on the load definition of Resolve, where require is used to dynamically load the controller definition file that the routing page relies on and perform data monitoring in its callback function, which returns a Promise object.

So how is this load method used?

The routing process looks like this:

  • Execute each method in Resolve and store the results of each method into the collection.
  • 2. Start instantiating the Controller object after all the resolve methods have been executed
  • 3. Instantiate the Controller object using the resolve result set as an argument. Here we use resolve only to load the dependencies of an HTML page when it is actually accessed. The return value of the load method does not need to be a parameter to the controller, so the method name can be defined arbitrarily.

Resolve controller injection problems

If a controller’s parameter data requires external injection, resolve provides the parameter injection factory to do so. For example, we define a Controller class that relies on a userData parameter and personInfo:

previewApp.controller('MyController', ['$scope', '$state', 'userData','personInfo',MyController]);

function MyController($scope, $state, $stateParams,userData,personInfo){

}
Copy the code

Before we can use MyController, we must solve the injection problem of these two parameters:

resolve: {
	load: ['$q', '$rootScope', function($q, $rootScope) {
	    var defer = $q.defer();
	    require(['other-controller'], function() {
		$rootScope.$apply(function() {
		    defer.resolve();
		});
	    });
	    return defer.promise;
	}],

	userData:function(){
		return {name:'wang',age:10}
	},
	personInfo:function(){
		return "Hello";
	}
    }
})
Copy the code

The resolve configuration needs to provide a property that is the same as the Controller parameter name, and whose value is that a factory method returns a data that is eventually passed to the Controller as a parameter.

In this case, the factory method name must be the same as the parameter name.

The revelation of

Resolve is used to prepare data, and only when the data is ready will the $stateChangeSuccess event be triggered to switch the route, then instantiate the Controller, and then update the template content.