AngularJS controller for a tab
Asked Answered
F

2

7

I have three tabs in my page. I'm using tabset and tab according to Angular Bootstrap Docs.

I set a controller for the <div> which has the tabsetas

<div ng-controller="Tabs" class="panel panel-default" id="tabs-panel"> 
  <tabset  class="panel-body">
    <tab heading="Tab 1"> </tab>
    <tab heading="Tab 2"> </tab>
    <tab heading="Tab 3"> </tab>
  </tabset>
</div>

The corresponding page is enter image description here

But, when I try to add another controller for my 2nd tab as

<div ng-controller="Tabs" class="panel panel-default" id="tabs-panel"> 
  <tabset  class="panel-body">
    <tab heading="Tab 1"> </tab>
    <tab heading="Tab 2" ng-controller="Tab2> </tab>
    <tab heading="Tab 3"> </tab>
  </tabset>
</div>

enter image description here

I now find that the heading is not displayed and I can no longer click the Tab2.

Why is that? How to get back the same functionality?

Is this the right way to add another controller in an existing controller?

My app.js :

var myApp = angular.module('myApp',['ui.bootstrap']);

myApp.controller('Tabs', function ($scope) {

});


myApp.controller('Tab2', function ($scope) {

});
Fascine answered 31/7, 2015 at 19:14 Comment(10)
Why would you want separate controllers for each tab?Burghley
I'm very new to angular and each tab of mine has different functions. So, I thought it is nice to have a controller for each tab.Fascine
I think unless you have a massive amount of functionality in each tab (in which case I would consider using a directive for the content), there is no need for separate controllers, you are just complicating it.Burghley
Moreover, each tab has almost same functionality, so using same ng-model might rise in namespace conflict.Fascine
What directive would you suggest? A new module for each tab?Fascine
A directive in general, not "which". By the way it sounds I would just use 1 controller though, name spacing aside. Like if you had a ton of logic or dom manipulation or whatever, make your own directive for the content of each tab (which will have it's own controller).Burghley
Okay! As far as I know directives can be anything - controllers, modules, models etc. So, what is that you want me to use?Fascine
I'm not saying necesarily to use it, but if you really want to separate your logic it is a good way to do it. You could have tab1 directive, tab2 directive and so on. But honestly, if you don't have that much content/functionality in each tab just use 1 controller...Burghley
I have the same problem. I'm pretty sure this problem is introduced by Angular 1.4.x. 1.3.x allows a controller for each tab. Initially I thought the problem was introduced by the new version of UI Bootstrap. After exclusive tests, I found the latest(0.14.3) version of UI Bootstrap works well with Angular 1.3.20.Romie
@Burghley does having separate controllers for each tab have any problem?Romie
D
6

I think there are at least three ways you could organize your controller code:

  1. Everything in one TabController
  2. Custom directive for each tab
  3. Add your tab logic to the tab callback function.

Please have a look at the demo below or here at jsfiddle.

It's the ui-bootstrap example code with the above mentioned points added.

angular.module('demoApp', ['ui.bootstrap'])
    .controller('TabsDemoCtrl', TabsController)
    .directive('sepecialTab', SpecialTab);

function TabsController($scope, $window) {
    $scope.tabs = [{
        title: 'Dynamic Title 1',
        content: 'Dynamic content 1'
    }, {
        title: 'Dynamic Title 2',
        content: 'Dynamic content 2',
        disabled: true
    }];

    $scope.alertMe = function () {
        setTimeout(function () {
            $window.alert('You\'ve selected the alert tab!');
        });
    };

    $scope.thirdTabCallback = function () {
        $scope.test = 'I\'m the third tab callback';

        $scope.clickme = function () {
            $window.alert('third tab only function');
        };
    };
}

function SpecialTab() {
    return {
        restrict: 'A',
        controller: function ($scope) {
            console.log('Special tab ctrl, runs on start.');
            $scope.hello = 'hello from special tab controller';
        }
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.1/ui-bootstrap-tpls.js"></script>
<div ng-app="demoApp" ng-controller="TabsDemoCtrl">
    <p>Select a tab by setting active binding to true:</p>
    <p>
        <button class="btn btn-default btn-sm" ng-click="tabs[0].active = true">Select second tab</button>
        <button class="btn btn-default btn-sm" ng-click="tabs[1].active = true">Select third tab</button>
    </p>
    <p>
        <button class="btn btn-default btn-sm" ng-click="tabs[1].disabled = ! tabs[1].disabled">Enable / Disable third tab</button>
    </p>
    <hr />
    <tabset>
        <tab heading="Static title">Static content</tab>
        <tab heading="Static title 2" sepecial-tab="">Static content2 {{hello}}</tab>
        <tab heading="Static title 3" select="thirdTabCallback()">Static content3 {{test}}
            <button ng-click="clickme()">click me</button>
        </tab>
        <tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disable="tab.disabled">{{tab.content}}</tab>
        <tab select="alertMe()">
            <tab-heading> <i class="glyphicon glyphicon-bell"></i> Alert!</tab-heading>I've got an HTML heading, and a select callback. Pretty cool!</tab>
    </tabset>
</div>
Delft answered 31/7, 2015 at 20:40 Comment(2)
Okay! But why can't I add another controller, like I did in my question. The example you cited is the same one which I used to make my code.Fascine
Angular-ui tab and ng-controller directives are requesting an isolated scope on the same element and that's not working (error in the console). But you could fix that by adding the ng-controller to a <div/> tag inside the tab. See this jsfiddle for an example.Delft
G
2

Here a custom directive to use in tabs, so I can use custom controllers for each tab.

angular.module('myModule', ['ui.bootstrap'])
  .directive('tabController', function() {
    return {
      restrict: 'A',
      controller: '@',
      name: 'tabController',
    }
  })
  .controller('MyCustomController', function() {
    var vm = this;
    vm.title = "Hey, I am The first controller";
  })
  .controller('MyCustomController2', function() {
    var vm = this;
    vm.title = "Hey, I am the second controller!";
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<html>

<div ng-app="myModule">


  <uib-tabset type="tabs">
    <uib-tab tab-controller="MyCustomController as ctrl">
      <uib-tab-heading>
        <span ng-bind="ctrl.title"></span>
      </uib-tab-heading>
      <p ng-bind="ctrl.title"></p>
    </uib-tab>
    <uib-tab tab-controller="MyCustomController2 as ctrl2">
      <uib-tab-heading>
        <span ng-bind="ctrl2.title"></span>
      </uib-tab-heading>
      <p ng-bind="ctrl2.title"></p>
    </uib-tab>

  </uib-tabset>

</div>
Godchild answered 6/2, 2017 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.