If you are looking to load your tab content dynamically from template urls based on the value of tabs available to the user as defined in $scope.tabs
, you should consider using a simple directive rather than ui-router views.
As you have already discovered ui-router will try and load the subviews regardless of whether they are referenced in the main view for that state.
We can however use our own directive to load templates, and therefore because the directive only runs when present in the main view, the templates load on demand.
template
Directive:
We create a template
directive, that allows us to pull in 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){
// 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 the $http
service to get the template from the server. Then it uses the $compile
service to apply the scope to the angular template, and renders it into the target element.
Usage:
Update the format of your main tabs template as below. Note we no longer reference ui-view
, instead we call our template
directive passing in the url
we want to load in the div
. With the current content of the div
being the loading indicator.
(If the controller
attribute is set the template will be wrapped with an <span>
having the ng-controller
attribute, so a template controller can 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>
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 puts the code given 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>
I hope this helps. If you have questions about something just ask.