AngularJS UI router named views lazy loading
AngularJS UI Router named loading view based on user access, not loading while accessing the state route.
Example:
$stateProvider
.state("login",
{
url: "/login",
templateUrl: getTemplateUrl("login/Index")
})
.state("main",
{
url: "/main",
views:
{
'': { templateUrl: getTemplateUrl('home/shell') },
'test1@main': { templateUrl: 'home/test1' },
'test2@main': { templateUrl: 'home/test2' },
'test3@main': { templateUrl: getTemplateUrl('home/test3') }
}
});
In the example above, when the user accesses the state main
, the UI router downloads all named html views from the server.
Question:
Can we load named-views when required below? I mean whenever we add a new tab dynamically and then only load the respectable html view from the server.
<tab ng-repeat="tab in tabs">
<div>
<div ui-view='{{tab.view}}'></div>
</div>
</tab>
source to share
If you want to dynamically load the contents of a tab from templated URLs based on the tab values available to the user as defined in $scope.tabs
, you should consider using a simple directive rather than the ui-router look.
As you already found out, ui-router will try to load subrequests, regardless of whether they refer to the main view of this state.
However, we can use our own directive to load templates, and because the directive only works when present in the main view, templates are loaded on demand.
template
Directive:
We create a directive template
that allows us to insert a template into an element html
.
.directive('template', ['$compile', '$http', function($compile, $http) {
return {
restrict: 'A',
replace: false,
link: function($scope, element, attrs) {
var template = attrs['template'];
var controller = attrs['controller'];
if(template!==undefined){
// Load the template
$http.get(template).success(function(html){
// Set the template
var e = angular.element(controller === undefined || controller.length === 0 ? html : "<span ng-controller='" + controller + "'>" + html + "</span>");
var compiled = $compile(e);
element.html(e);
compiled($scope);
});
}
}
};
}]);
So this code uses a service $http
to get the template from the server. Then it uses the service $compile
to apply the scope to the angular template and renders it to the target element.
Using:
Update the format of the main tab template as shown below. Note that we are not referencing anymore ui-view
, instead we name our directive template
passing in url
that we want to load in div
. If the current content div
is a loading indicator.
(If the attribute is set controller
, the template will be wrapped with an <span>
attribute ng-controller
, so a templated controller can be used. This is optional.)
in home/shell
:
<tab ng-repeat="(tabName,tab) in tabs">
<div template='{{tab.template}}' controller="{{tab.controller}}">Loading {{tabName}} ...</div>
</tab>
Then set the tabs you want to display:
$scope.tabs = {
'tab1': { template: 'home/tab1'},
'tab2': { template: 'home/tab2', controller: 'Tab2Controller' },
'tab3': { template: 'home/tab3'}
};
Full source:
This just adds the code above as an example AngularJS app. Assumes the template paths are valid, i.e. home/shell
, home/tab1
etc.
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<meta charset="utf-8">
<title>Angular Views</title>
</head>
<body ng-app="myTabbedApp">
<div ui-view></div>
<script>
angular.module('myTabbedApp', ['ui.router'])
/* Controller for the Main page ie. home/shell */
.controller('MainPageTabController', ['$scope', function($scope) {
// Set the page tabs dynamically as required by your code
$scope.tabs = {
'tab1': { template: 'home/tab1'},
'tab2': { template: 'home/tab2', controller: 'Tab2Controller' },
'tab3': { template: 'home/tab3'}
};
}])
/* Example controller for Tab 2 */
.controller('Tab2Controller', ['$scope', function($scope) {
$scope.hello = "world";
}])
/* State provider for ui router */
.config(['$stateProvider', function($stateProvider){
$stateProvider
.state("login",
{
url: "/login",
templateUrl: "login/index"
})
.state("main",
{
url: "/main",
templateUrl: 'home/shell',
controller: 'MainPageTabController'
});
}])
/* Directive to load templates dynamically */
.directive('template', ['$compile', '$http', function($compile, $http) {
return {
restrict: 'A',
replace: false,
link: function($scope, element, attrs) {
var template = attrs['template'];
if(template!==undefined){
// Load the template
$http.get(template).success(function(html){
// Set the template
var e = angular.element(html);
var compiled = $compile(e);
element.html(e);
compiled($scope);
});
}
}
};
}]);
</script>
</body>
</html>
Hope this helps. If you have questions about something, just ask.
source to share