I am attempting to lazy load a controller and template in my UI-Router router.js file, but am having difficulty with the template.
The controller loads properly, but after that is loaded, we must load the template and this is where things go wrong.
After ocLazyLoad loads the controller, we resolve an Angular promise which is also included in the templateProvider. The issue is instead of returning the promise (templateDeferred.promise) after the file is done loading, the promise is returned as an object.
.state('log_in', {
url: '/log-in',
controller: 'controllerJsFile',
templateProvider: function($q, $http) {
var templateDeferred = $q.defer();
lazyDeferred.promise.then(function(templateUrl) {
$http.get(templateUrl)
.success(function(data, status, headers, config) {
templateDeferred.resolve(data);
}).
error(function(data, status, headers, config) {
templateDeferred.resolve(data);
});
});
return templateDeferred.promise;
},
resolve: {
load: function($templateCache, $ocLazyLoad, $q) {
lazyDeferred = $q.defer();
var lazyLoader = $ocLazyLoad.load ({
files: ['src/controllerJsFile']
}).then(function() {
return lazyDeferred.resolve('src/htmlTemplateFile');
});
return lazyLoader;
}
},
data: {
public: true
}
})
Ok, thanks for the responses, but I have figured it out.
.state('log_in', {
url: '/log-in',
controller: 'controllerJsFile',
templateProvider: function() { return lazyDeferred.promise; },
resolve: {
load: function($templateCache, $ocLazyLoad, $q, $http) {
lazyDeferred = $q.defer();
return $ocLazyLoad.load ({
name: 'app.logIn',
files: ['src/controllerJsFile.js']
}).then(function() {
return $http.get('src/htmlTemplateFile.tpl.html')
.success(function(data, status, headers, config) {
return lazyDeferred.resolve(data);
}).
error(function(data, status, headers, config) {
return lazyDeferred.resolve(data);
});
});
}
},
data: {
public: true
}
})
So, after some more reading, I realized I had an issue with my promises. We create one called lazyDeferred which is the one to be returned to templateProvider and is declared as a global variable. templateProvider waits for the promise to be fulfilled.
After we load our controller, we create an XHR/ $http request to retrieve the template file. $http.get is a promise so we can return that, $ocLazyLoad.load also is a promise so we can return that as well. Finally, we just need to resolve the lazyDeferred one and that I think balloons through the promises and resolves all of them.
I apologize if this was not very clear, I'm not 100% sure of how this works.
In case you'd like to lazily load the controller, I would suggest follow these detailed answers:
- requirejs with angular - not resolving controller dependency with nested route
- angular-ui-router with requirejs, lazy loading of controller
In case we need to load dynamically the HTML template, it is much more easier. There is an example from this Q & A
- Trying to Dynamically set a templateUrl in controller based on constant
(the working plunker)
$stateProvider
.state('home', {
url: '/home',
//templateUrl: 'index5templateA.html', (THIS WORKS)
templateProvider: function(CONFIG, $http, $templateCache) {
console.log('in templateUrl ' + CONFIG.codeCampType);
var templateName = 'index5templateB.html';
if (CONFIG.codeCampType === "svcc") {
templateName = 'index5templateA.html';
}
var tpl = $templateCache.get(templateName);
if(tpl){
return tpl;
}
return $http
.get(templateName)
.then(function(response){
tpl = response.data
$templateCache.put(templateName, tpl);
return tpl;
});
},
You can check these as well:
- Angular UI Router: decide child state template on the basis of parent resolved object
- Angular and UI-Router, how to set a dynamic templateUrl