7

I'm working with AngularJS and UI-Bootstrap on a project with ui-tabs.

The rough layout is this:

<uib-tabset>
    <uib-tab ng-repeat="tab in tabs" heading="{{tab.TAB_NAME}} : {{tab.Questions|sumByKey:'count'}} of {{tab.Questions.length}}" active="tab.active" disable="tab.disabled">

    <!-- Repeated Content -->

    </uib-tab>
</uib-tabset>

sumByKey:'count' is a filter that calculates the sum of the 'count' field in the repeated tab object. This tracks questions that have been answered, and tab.Questions.length counts the number of questions repeated in the tab.

I can display both in the tab name as I'm doing here, and this works, so in each tab the Tab name is the name : questions-answered of total-questions, i.e.: 'Parking: 1 of 5'.

What I'm trying to do is use ng-class to add a 'completed' class to the tab when these numbers are equal, and all the questions in that tab have been answered.

I can add a class='complete' to the tab, and that works, but trying to make any use of ng-class doesn't work at all, not even ng-class="complete".

Is there a way to do this? Can ng-class be used with uib-tabs? Is there some other mechanism to evaluate an expression and modify the class on the tab?

3 Answers 3

14

I'm afraid you can't use ng-class directly on the ui-tab. The issue here is that the contents (and attributes) of the ui-tab is transcluded into this. Which has its own ng-class that's clobbering yours. Here's the only workaround I've managed to find/use.

Use class along with ng-class like this:

<uib-tabset>
    <uib-tab class="{{complete}}" ng-repeat="tab in tabs" heading="{{tab.TAB_NAME}} : {{tab.Questions|sumByKey:'count'}} of {{tab.Questions.length}}" active="tab.active" disable="tab.disabled">

    <!-- Repeated Content -->

    </uib-tab>
</uib-tabset>

Note, however, that complete will have to be a string for it to work properly. If it's a boolean, you'd probably have better luck doing:

<uib-tabset>
    <uib-tab class="{{complete ? 'complete':''}}" ng-repeat="tab in tabs" heading="{{tab.TAB_NAME}} : {{tab.Questions|sumByKey:'count'}} of {{tab.Questions.length}}" active="tab.active" disable="tab.disabled">

    <!-- Repeated Content -->

    </uib-tab>
</uib-tabset>

Should you need to put multiple classes, I'd create a function that returns the classes in a string:

<uib-tabset>
    <uib-tab class="{{isCompleted}}" ng-repeat="tab in tabs" heading="{{tab.TAB_NAME}} : {{tab.Questions|sumByKey:'count'}} of {{tab.Questions.length}}" active="tab.active" disable="tab.disabled">

    <!-- Repeated Content -->

    </uib-tab>
</uib-tabset>

In controller:

$scope.isCompleted = function () {
    // some logic
    return 'complete done';
}

Hope that helps you somewhat.

Sign up to request clarification or add additional context in comments.

Comments

0

Many thanks jsonmurphy! This had been making my head hurt for some time, and this worked like a charm!

Final syntax is this:

class="{{ (tab.Questions|sumByKey:'count') == (tab.Questions.length) ? 'completed' : ''}}"

Then added these to the CSS:

li.completed a.ng-binding{
    background-color: silver;
}

li.active.completed a.ng-binding{
    background-color: silver;
}

This sets the tab background for the whole tab to silver when all the questions in that tab have been answered. The li.completed and li.active.completed cover both when the tab is currently selected (.active), and when the tab is completed but not the current tab. They could have been written as a single rule, but I kept them separate for clarity.

Comments

0

As indicated above we can't use ng-class for this but uib-tab has provided a classes attribute you can use for this.

As indicated in the documentation. https://angular-ui.github.io/bootstrap/#!#tabs

Below is a working example showing classes can be changed dynamically.

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

app.controller('controller', ['$scope', function($scope) {
    var classOne = 'bg-success';
    var classTwo = 'bg-danger';

    $scope.swapClasses = function() {
      var tempHolder = classOne;
      classOne = classTwo;
      classTwo = tempHolder;
    }

    $scope.getClassOne = function() {
      return classOne;
    }

    $scope.getClassTwo = function() {
      return classTwo;
    }
  }

]);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.1.3/ui-bootstrap-tpls.js"></script>


<body ng-app="example">
  <div ng-controller="controller">
    <div>
      <input type="checkbox" ng-click="swapClasses()" /> Swap Classes!
    </div>
    <br>
    <uib-tabset>
      <uib-tab heading='Tab One' classes="{{getClassOne()}}">

        <div class="tab-container">
          I am Tab One
        </div>
      </uib-tab>


      <uib-tab heading='Tab Two' classes="{{getClassTwo()}}">

        <div class="tab-container">
          I am Tab Two
        </div>
      </uib-tab>
    </uib-tabset>

  </div>
</body>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.