AngularJS - Use multiple controllers across bootstrap tabs - angularjs

I'd like to divide content with bootstrap tabs. This works fine except the html breaks when I attach the ng-controller in parent elements. Is there a way to use html elements to insert ng-controller without affecting the hierarchy necessary to display tabs in bootstrap?
Working tab layout:
<div ng-app="myApp">
<div class="tab-content">
<div id="tab1" class="tab-pane fade in active">{{ tab1_content }}</div>
<div id="tab2" class="tab-pane fade in">{{ tab2_content }}</div>
<div id="tab3" class="tab-pane fade in">{{ tab3_content }}</div>
</div> <!-- all tab-content -->
</div> <!-- end myApp -->
How I'd like to use my controllers (breaks the tab displays by putting content in all tabs:
<div ng-app="myApp">
<div class="tab-content">
<ng-controller ng-controller="test_controller1">
<div id="tab1" class="tab-pane fade in active">{{ tab1_content }}</div>
<div id="tab2" class="tab-pane fade in">{{ tab2_content }}</div>
</ng-controller> <!-- end test_controller1 -->
<ng-controller ng-controller="test_controller2">
<div id="tab3" class="tab-pane fade in">{{ tab3_content }}</div>
</ng-controller> <!-- end test_controller2 -->
</div> <!-- all tab-content -->
</div> <!-- end myApp -->
Demo: https://jsfiddle.net/L2b4yLfa/

Is this acceptable?
I have initialized the same controller for two tabs. Since its a small window the code snippet output will show mobile view. click on run code snippet -> full page
angular.module('myApp', []);
angular.module('myApp').controller('test_controller1', function($scope) {
$scope.tab1_content = "Tab One Content";
$scope.tab2_content = "Tab Two Content";
});
angular.module('myApp').controller('test_controller2', function($scope) {
$scope.tab3_content = "Tab Three Content";
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle pull-left" data-toggle="collapse" data-target="#myNavbar"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button>
<a class="navbar-brand" href="#">Title</a>
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li class="active"><a data-toggle="tab" href="#tab1">Tab 1</a></li>
<li><a data-toggle="tab" href="#tab2">Tab 2</a></li>
<li><a data-toggle="tab" href="#tab3">Tab 3</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>Testing</li>
</ul>
</div>
</div>
</nav>
<div ng-app="myApp">
<div class="tab-content">
<div id="tab1" ng-controller="test_controller1" class="tab-pane fade in active">{{ tab1_content }}</div>
<div id="tab2" ng-controller="test_controller1" class="tab-pane fade in">{{ tab2_content }}</div>
<div id="tab3" ng-controller="test_controller2" class="tab-pane fade in">{{ tab3_content }}</div>
</div> <!-- all tab-content -->
</div> <!-- end myApp -->
So in the future you would need to share data between the same controller for the two tabs using services.

My solution was to switch to angular bootstrap ui, not use the built-in uib-tabs and use $rootscope to handle the 'active_tab' value.
<style> .uib-tab.nav-item { display:none; } .nav-tabs { border-bottom: inherit; } </style>
<div ng-app="myApp">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" ng-click="navCollapsed = !navCollapsed">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Title</a>
</div> <!-- end navbar-header -->
<div class="collapse navbar-collapse" uib-collapse="navCollapsed">
<ul class="nav navbar-nav">
<li ng-class="{active: active_tab == 1}" ng-click="active_tab = 1">Tab 1</li>
<li ng-class="{active: active_tab == 2}" ng-click="active_tab = 2">Tab 2</li>
<li ng-class="{active: active_tab == 3}" ng-click="active_tab = 3">Tab 3</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>Selected Tab: {{ active_tab }}</li>
</ul>
</div> <!-- end uib-collapse -->
</nav> <!-- end nav -->
<uib-tabset active="active_tab">
<ng-controller ng-controller="test_controller1">
<uib-tab index="1" heading="heading not displayed">1: {{ tab1_content }}</uib-tab>
<uib-tab index="2" heading="heading not displayed">2: {{ tab2_content }}</uib-tab>
</ng-controller>
<ng-controller ng-controller="test_controller2">
<uib-tab index="3" heading="heading not displayed">3: {{ tab3_content }}</uib-tab>
</ng-controller>
</uib-tabset>
</div>
Demo: https://plnkr.co/edit/36tkl3pCV7hgNz8rbpTq?p=preview

Related

AngularJS - ng-include template behaves differently

I'm struggling with understanding why ng-include template seems to break my angular application.
I have some ui bootstrap tab issues with multiple controllers and went with this design which works (note I cannot use the built in tab switching across multiple controllers, so it is hidden):
https://plnkr.co/edit/hCCVFt58OXztZDQtxGIS?p=preview
However, simply moving the nav section to a template breaks the tab switching:
https://plnkr.co/edit/Lbh2Pw2wiZAS6oZTwX47?p=preview
The variable 'active_tab' seems to update correctly... but I'm guessing the scope changes when it is in the template?
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" ng-click="navCollapsed = !navCollapsed">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Title</a>
</div> <!-- end navbar-header -->
<div class="collapse navbar-collapse" uib-collapse="navCollapsed">
<ul class="nav navbar-nav">
<li ng-class="{active: active_tab == 1}" ng-click="active_tab = 1">Tab 1</li>
<li ng-class="{active: active_tab == 2}" ng-click="active_tab = 2">Tab 2</li>
<li ng-class="{active: active_tab == 3}" ng-click="active_tab = 3">Tab 3</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>Selected Tab: {{ active_tab }}</li>
</ul>
</div> <!-- end uib-collapse -->
</nav> <!-- end nav -->
<uib-tabset active="active_tab">
<ng-controller ng-controller="test_controller1">
<uib-tab index="1" heading="tab 1">1: {{ tab1_content }}</uib-tab>
<uib-tab index="2" heading="tab 2">2: {{ tab2_content }}</uib-tab>
</ng-controller>
<ng-controller ng-controller="test_controller2">
<uib-tab index="3" heading="tab 3">3: {{ tab3_content }}</uib-tab>
</ng-controller>
</uib-tabset>

Navbar works but clicked element not highlighted

I generated an AngularJS app with yeoman. The navbar works and when I click on the an element the enw page loads, however the clicked button don't get highlighted.
This is the navbar code
<div class="header">
<div class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#js-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#!/">myApp</a>
</div>
<div class="collapse navbar-collapse" id="js-navbar-collapse">
<ul class="nav navbar-nav">
<li class="active">1</li>
<li><a ng-href="#!/page2">2</a></li>
<li><a ng-href="#!/page3">3</a></li>
<li><a ng-href="#!/page4">4</a></li>
<li><a ng-href="#!/page5">5</a></li>
<li><a ng-href="#!/page6">6</a></li>
</ul>
</div>
</div>
</div>
</div>
There are many ways you can do this. Here there is one of them
Create a controller and set a var called currentLink like this
//...
.controller('headerCtrl', function($scope){
$scope.currentLink = 1;
$scope.set = function(link){
$scope.currentLink = link;
}
});
//...
now in your html modify your code like this:
<div class="header" ng-controller="headerCtrl">
<!--...-->
<div class="collapse navbar-collapse" id="js-navbar-collapse">
<ul class="nav navbar-nav">
<li ng-class="{'active': currentLink == 1}">1</li>
<li ng-class="{'active': currentLink == 2}"><a ng-href="#!/page2" ng-click="headerCtrl.set(2);">2</a></li>
<li ng-class="{'active': currentLink == 3}" ><a ng-href="#!/page3" ng-click="headerCtrl.set(3);">3</a></li>
<li ng-class="{'active': currentLink == 4}"><a ng-href="#!/page4" ng-click="headerCtrl.set(4);">4</a></li>
<!-- and so on-->
</ul>
<!--...-->
</div>
This way with ng-class you switch from active or not every link and with ng-click you set that link as active when clicked;

Implement UI Bootstrap tabs in sidebar

I am using UI Bootstrap with AngularJS and I am trying to separate the vertical tabs into a sidebar using col-md-2 and col-md-10.
Currently the I have...
<uib-tabset active="activePill" vertical="true" type="pills">
<uib-tab heading="Tab 1">Vertical content 1</uib-tab>
<uib-tab heading="Tab 2">Vertical content 2</uib-tab>
<uib-tab heading="Tab 3">Vertical content 3</uib-tab>
</uib-tabset>
... which outputs ...
<div active="activePill" vertical="true" type="pills" class="ng-isolate-scope">
<ul class="nav nav-pills nav-stacked" ng-class="{'nav-stacked': vertical, 'nav-justified': justified}" ng-transclude="">
<li ng-class="[{active: active, disabled: disabled}, classes]" class="uib-tab nav-item ng-scope ng-isolate-scope active" heading="Tab 1">
Tab 1
</li>
<li ng-class="[{active: active, disabled: disabled}, classes]" class="uib-tab nav-item ng-scope ng-isolate-scope" heading="Tab 2">
Tab 2
</li>
<li ng-class="[{active: active, disabled: disabled}, classes]" class="uib-tab nav-item ng-scope ng-isolate-scope" heading="Builds">
Tab 3
</li>
</ul>
<div class="tab-content">
<!-- ngRepeat: tab in tabset.tabs -->
<div class="tab-pane ng-scope active" ng-repeat="tab in tabset.tabs" ng-class="{active: tabset.active === tab.index}" uib-tab-content-transclude="tab">
<span class="ng-scope">Vertical content 1</span>
</div>
<!-- end ngRepeat: tab in tabset.tabs -->
<div class="tab-pane ng-scope" ng-repeat="tab in tabset.tabs" ng-class="{active: tabset.active === tab.index}" uib-tab-content-transclude="tab">
<span class="ng-scope">Vertical content 2</span>
</div>
<!-- end ngRepeat: tab in tabset.tabs -->
<div class="tab-pane ng-scope" ng-repeat="tab in tabset.tabs" ng-class="{active: tabset.active === tab.index}" uib-tab-content-transclude="tab">
<span class="ng-scope">Vertical content 3</span>
</div>
<!-- end ngRepeat: tab in tabset.tabs -->
</div>
</div>
I would like to have ...
<div active="activePill" vertical="true" type="pills" class="ng-isolate-scope">
<ul class="nav nav-pills nav-stacked col-md-2" ng-class="{'nav-stacked': vertical, 'nav-justified': justified}" ng-transclude="">
<!-- snip -->
</ul>
<div class="tab-content col-md-10">
<!-- snip -->
</div>
</div>
(added col-md-2 and col-md-10)
My team once tackled this and I don't think you can position them on the side (it has to do with how the directive is structured), so we had to remove the body directives, shrink the tabs container and show state views on a different div on the right.
<div class="col-sm-2">
<uib-tabset active="active" vertical="true" type="pills">
<uib-tab heading="Tab 1" select="selected(1)"></uib-tab>
<uib-tab heading="Tab 2" select="selected(2)"></uib-tab>
<uib-tab heading="Tab 3" select="selected(3)"></uib-tab>
</uib-tabset>
</div>
<div class="col-sm-10">
<div ng-show="selectedView===1">
Show what tab 1 is selected
</div>
<div ng-show="selectedView===2">
Show what tab 2 is selected
</div>
<div ng-show="selectedView===3">
Show what tab 3 is selected
</div>
</div>
Sample plunker
This is of course a simplified case, what we did was, using ui-router to show different states on the right, that made it a more "genuine" nav-bar and we didn't have to repeat the ugly <div ng-show="selectedView===#"> markup parts.

Bootstrap nav-tabs not working with Angular $routeprovider

I am using AngularJs and Bootstrap. While I am using $RouteProvider for SPA, I am using bootstrap for the layout. This is working fine.
However, I am now trying to use Bootstrap nav-tabs to have tab based navigations.
My HTML is like this:
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#/mis"><i class="fa fa-tachometer"></i> TrigonMeter</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div id="navbar" class="navbar-collapse collapse">
<ul id="tabs" class="nav navbar-nav nav-tabs container-fluid" data-tabs="tabs">
<li class="active"><a data-target="#db" href="#db" data-toggle="tab">Dashboard</a></li>
<li><a data-target="#admin" href="#admin" data-toggle="tab">Admin</a></li>
<li><a data-target="#mis" href="#mis" data-toggle="tab">MIS</a></li>
<li><a data-target="#fin" href="#fin" data-toggle="tab">Finance</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="nav-link">Hi {{globals.currentUser.username}}</li>
<li><span class="glyphicon glyphicon-log-out"></span>Logout</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</nav>
For the tabs. This works fine. And the following is the tab-content section:
<div class="container-fluid">
<!--[if lt IE 7]>
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>
<![endif]-->
<div class="row">
<div id="my-tab-content" class="tab-content col-sm-2 col-md-2 sidebar">
<div class="tab-pane active" id="db">
<h1>Dashboard</h1>
<ul>
<li>Organisation Details</li>
<li>Job Numbers</li>
<li>Job Expenses</li>
<li>Job Financial Details</li>
<li>Contracts</li>
</ul>
</div>
<div class="tab-pane" id="admin">
<h1>Admin</h1>
<p>Organisation Details</p>
</div>
<div class="tab-pane" id="mis">
<h1>MIS</h1>
<ul>
<li>Job Numbers</li>
<li>Job Expenses</li>
<li>Job Financial Details</li>
<li>Contracts</li>
</ul>
</div>
<div class="tab-pane" id="fin">
<h1>Finance</h1>
<p>orange orange orange orange orange</p>
</div>
</div>
<div class="col-sm-10 col-md-10">
<div ng-view></div>
</div>
</div>
</div>
But The tab-content section is not working.
Please do let me know if I could explain the problem.
Is there a way to do this?

The `content div of a tab` is not showing up.. I am using AngularJS to accomplish this

In reference to the answer by Sergey Romanov
Only vertical tabs show up... The tab content div never gets displayed when I used his code.
Here is my code
<div class="row">
<div class="col-sm-3">
<ul class="nav nav-tabs nav-stacked nav-pills" role="tablist">
<li ng-class="{'active': view_tab == 'tab1'}">
<a class="btn-lg" ng-click="changeTab('tab1')" href="">My Tab 1</a>
</li>
<li ng-class="{'active': view_tab == 'tab2'}">
<a class="btn-lg" ng-click="changeTab('tab2')" href="">My Tab 2</a>
</li>
</ul>
</div>
<div class="col-sm-9">
<div class="tab-content">
<div class="tab-pane" ng-show="view_tab == 'tab1'">
This is tab 1 content
</div>
<div class="tab-pane" ng-show="view_tab == 'tab2'">
This is tab 2 content
</div>
</div>
var NavController = function ($scope,$http) {
$scope.changeTab = function(tab) {
$scope.view_tab = tab;
}
};
NavController.$inject = ['$scope','$http'];
angular.module('publisherApp').controller('NavController', NavController);
For Bootstrap tab content you need to set which tab is active:
var NavController = function($scope, $http) {
$scope.changeTab = function(tab) {
$scope.view_tab = tab;
}
};
NavController.$inject = ['$scope', '$http'];
angular.module('app', []).controller('NavController', NavController);
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app' ng-controller='NavController'>
<div class="col-sm-3">
<ul class="nav nav-tabs nav-stacked nav-pills" role="tablist">
<li ng-class="{'active': view_tab == 'tab1'}">
<a class="btn-lg" ng-click="changeTab('tab1')" href="">My Tab 1</a>
</li>
<li ng-class="{'active': view_tab == 'tab2'}">
<a class="btn-lg" ng-click="changeTab('tab2')" href="">My Tab 2</a>
</li>
</ul>
</div>
<div class="col-sm-9">
<div class="tab-content">
<div class="tab-pane" ng-class="{active: view_tab == 'tab1'}">
This is tab 1 content
</div>
<div class="tab-pane" ng-class="{active: view_tab == 'tab2'}">
This is tab 2 content
</div>
</div>
</div>
</div>

Resources