1

I'm using Bootstrap and AngularJS to dynamically create clickable tabs in HTML. More specifically, I'm using the ng-switch and ng-switch-when directives to control which tab's content is displayed at any given time.

PLEASE NOTE: Below you'll notice I use a controller for DOM manipulation. I realize the "AngularJS way" to perform DOM manipulation is with directives (and not controllers). I'm not one to deliberately violate good coding practices, but since I'm trying to understand this exact issue I've stumbled across while learning about controllers and directives, I'm asking you to only consider using a controller for now since that's what I believe may be contributing to the issue.

If you keep reading you'll notice I've already found a directive-based solution (i.e., the "AngularJS way"), but I'm specifically asking about the issue that occurs when using a controller and ng-switch-when.

The Problem:

The issue I'm facing is as follows. When I append div tags (containing a ng-switch-when directive) onto a container, and then compile these tags using $compile, somehow the content of each tag using ng-switch-when becomes duplicated. To keep this question from becoming too long, I've placed the idea behind what the code's expected behavior is in the comments of the first JSFiddle below, which demonstrates the issue.

JSFiddle: What I have now -- Uses controller for DOM manipulation ("non-AngularJS way"), results in unexpected duplication of tags using ng-switch-when.

An in-depth description of how to reproduce the duplication is as follows. Upon creating a new tab, it appears that the previously clicked tab's content (within the div containing ng-switch-when) is duplicated. You can see this happen by loading the above JSFiddle, right-clicking the Default text, selecting Inspect element, and then pressing Analysis > Create Tab in the tabbed pane. You'll see there are now two div tags with ng-switch-when="Default" instead of just one. If you continue to create new tabs, this pattern continues for view1, view2, and so on. Alternatively, just click Analysis > Create Tab 5 times and then look at the duplicates in Tabs 1-4. Either way, you'll see the previously selected tab's contents are doubled whenever a new tab is created.

Frustrated by this unexpected behavior, I went ahead and implemented a directive-based solution using AngularUI's Bootstrap components, which creates custom directives for tab components, to gain the desired functionality.

JSFiddle: What I want to happen in the above JSFiddle -- Uses directives for DOM manipulation ("AngularJS way").

However, as I've mentioned, I want to know why my first JSFiddle is not working. See below for formal question.

Points to consider:

  • The issue may be related to scope, the order the scripts are loaded, or possibly a logic error.
  • Perhaps it's something AngularJS simply cannot do. I'm aware that compound transclusion no longer works as of v1.2, and this issue may be related.

So my question is as follows:

Why is this duplication occurring? Is there a way to prevent/workaround the duplicates from being created? Remember, I wouldn't use this in practice, I'm just curious if this issue can be solved at all.

PLEASE NOTE: I am not looking to resolve this using jQuery, such as this jQuery solution. Although I'm aware AngularJS uses a lighter version of jQuery called jqLite under the hood, I'm looking for a "pure AngularJS" solution.

HTML:

<!-- Include CDNs (see JSFiddle above) -->
<!-- Wrap in HTML tags, include DOCTYPE -->
<body ng-app="myApp">
    <div class="panel panel-default" ng-controller="myCtrl">
        <div class="panel-heading">
            <ul class="nav nav-tabs">
                <li class="active">
                    <a class="h4">My App</a>
                </li>
                <li class="dropdown">
                    <a href="" class="dropdown-toggle h4" data-toggle="dropdown">
                        Analysis
                        <span class="caret"></span>
                    </a>
                    <ul class="dropdown-menu">
                        <li>
                            <button id="createTabLink" class="h4" ng-click="createTabClick()">Create Tab</button>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
        <div class="panel-body">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <ul id="createTabDiv" class="nav nav-tabs"></ul>
                </div>
                <div class="panel-body">
                    <div id="viewWrapper" ng-switch="" on="viewSelected">
                        <div id="Default" ng-switch-when="Default">Default</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

JS:

angular.module('myApp', []);

function myCtrl($scope, $compile) {
    $scope.count = 0;
    $scope.viewSelected = "Default";

    $scope.tabClick = function($event) {
        var tab = $event.target;
        var viewName = tab.getAttribute("value");
        $scope.viewSelected = viewName;
    };

    $scope.createTabClick = function() {
        $scope.count++;
        var viewName = "view" + $scope.count;
        var createTabDiv = angular.element(document.querySelector('#createTabDiv'));
        var viewWrapper = angular.element(document.querySelector('#viewWrapper'));
    
        var $comp1 = createTabDiv.append('<li class="active"><a class="h4" value="' + viewName + '" ng-click="tabClick($event)">Tab ' + $scope.count + '</a></li>');
        $compile($comp1)($scope);
        var $comp2 = viewWrapper.append('<div id="' + viewName + '" ng-switch-when="' + viewName + '">' + viewName + '</div>');
        $compile($comp2)($scope);
    
        $scope.viewSelected = viewName;
    };
}
Community
  • 1
  • 1
bunting
  • 687
  • 1
  • 6
  • 11
  • Possible duplicate of [Angular.js ng-switch-when not working with dynamic data?](http://stackoverflow.com/questions/21566118/angular-js-ng-switch-when-not-working-with-dynamic-data) – Paul Sweatte Dec 30 '15 at 01:42

0 Answers0