For those interested in loading tab content dynamically from template URLs based on the available tabs in $scope.tabs
, using a simple directive instead of ui-router views may be a better option.
It has been noted that ui-router will attempt to load subviews even if they are not referenced in the main view for that state.
However, by creating our own directive to load templates, we can ensure that the templates are only loaded when necessary since the directive only runs when present in the main view.
template
Directive:
We establish a custom template
directive that enables us to fetch a template into an html
element.
.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){
// Retrieve 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);
});
}
}
};
}]);
This code utilizes the $http
service to fetch the template from the server and then applies the scope to the Angular template using the $compile
service, rendering it into the target element.
Usage:
To implement this approach, update the structure of your main tabs template as shown below. Instead of referencing ui-view
, utilize the template
directive with the specified url
to load within the div
, with the current content displaying a loading indicator.
(If the controller
attribute is provided, the template will be enclosed in a <span>
with the ng-controller
attribute, allowing a template controller to be applied. This is optional.)
in home/shell
:
<tab ng-repeat="(tabName,tab) in tabs">
<div template='{{tab.template}}' controller="{{tab.controller}}">Loading {{tabName}} ...</div>
</tab>
Subsequently, specify the tabs to be displayed:
$scope.tabs = {
'tab1': { template: 'home/tab1'},
'tab2': { template: 'home/tab2', controller: 'Tab2Controller' },
'tab3': { template: 'home/tab3'}
};
Full source:
The following example presents the previously mentioned code as an illustrative AngularJS application. It assumes valid template paths such as 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) {
// Specify the page tabs dynamically as required
$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){
// Retrieve 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>
If you have any questions or need clarification on any part, feel free to ask.