javascripthtmlangularjsangularjs-directiveangularjs-templates

Not able to apply a directive to two different controllers in AngularJS


Fiddler link

I am using Tippy library to create an HTML tooltip. I made 2 directives to handle the tippy tooltip.

.directive('settings', function() {
    return {
      templateUrl: 'tippy-template.html'
    };
  })
  .directive('tippy', function() {
    return function (scope) {
      tippy('.tippy', {
           position: 'bottom',
           animation: 'shift',
           arrow: true,
           interactive: true,
           arrowSize: 'big',
           distance: 20,
           html: document.getElementById('setting-template'),
           appendTo: document.getElementById('settings-controller')
      })
    };
  })

The settings directive contains the HTML tooltip code and the tippy directive will be placed in the HTML tooltip code to get it activated. The tippy tool shares data with the controller it is in, in this example it shares cache.

Everything works fine if there is only one instance of tippy Fiddler 1 controller. I am not able to use the directive again. I was able to recreate the issue I'm having, Fiddler 2 controllers link.

enter image description here From my understanding, Tippy can only be used if there is a unique id. Is there a way to solve this?

tippy-template.html

<div id="setting-template" tippy>
   <ul class="collection">
     <li class="collection-item">
       <div class="col-title"><b>{{title}}</b></div>
       <div class="col-title">Cache</div>
       <div class="col-item">
         <div class="switch">
           <label>Off
                <input ng-model="cache" type="checkbox"><span class="lever"></span> On
           </label>
         </div>
       </div>
     </li>
     <li class="collection-item">
       <div class="col-title"><b>Cache Result</b></div>
       <div class="col-item">{{cache}}</div>
    </li>
  </ul>
</div>

Directive usage (Inside a Controller)

<div id="settings-controller" settings></div>

Solution

  • after wreaking my brain on what I was doing wrong, I finally got the solution. You basically need to create a unique IDs for the class (.tippy) and I basically used the elements directly, You were saying that document.getElementById() is needed for it to work, but $element[0] does the same thing. Figured that out by logging both the outputs in the console. Anyway please check the below fiddle with the solution.

    JSFiddle Demo

    HTML:

    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" 
      rel="stylesheet">
    <body ng-app="myapp">
       <div class="row">
         <!-- CONTROLLER 2-->
         <div class="col s12 m6" ng-controller="controller1">
            <div class="card fill1">
               <div class="card-content">
                  <span class="card-title">{{title}}</span>
                  <i class="material-icons tippy c-pointer" data-theme="light" data-trigger="click" data-interactive="true" data-animatefill="false" data-arrow="true">settings</i>
                  <div id="settings-controller2" parent="tippy" settings></div>
                  <div class="filler"></div>
                  Cache is : <b>{{cache}}</b>
               </div>
            </div>
         </div>
    
         <!-- CONTROLLER 2-->
         <div class="col s12 m6" ng-controller="controller2">
            <div class="card">
               <div class="card-content">
                  <span class="card-title">{{title}}</span>
                  <i class="material-icons tippy2 c-pointer" data-theme="light" data-trigger="click" data-interactive="true" data-animatefill="false" data-arrow="true">settings</i>
                  <div id="settings-controller" parent="tippy2" settings></div>
                     <div class="filler"></div>
                     Cache is : <b>{{cache}}</b>
               </div>
            </div>
         </div>
      </div>
       <script type="text/ng-template" id="tippy-template.html">
          <div id="setting-template" tippy>
                    <ul class="collection">
                <li class="collection-item">
                <div class="col-title"><b>{{title}}</b></div>
                <div class="col-title">Cache</div>
                <div class="col-item">
                    <div class="switch">
                    <label>Off
                                    <input ng-model="cache" type="checkbox"><span class="lever"></span>
                    On</label>
                  </div>
                </div>
               </li>
               <li class="collection-item">
                <div class="col-title"><b>Cache Result</b></div>
                    <div class="col-item">{{cache}}</div>
               </li>
              </ul>
             </div>
        </script>
    </body>
    

    JS:

    var myapp = angular.module('myapp', [])
    
    .directive('settings', function() {
        return {
          templateUrl: 'tippy-template.html',
          controller: function($scope, $element, $attrs){
            $scope.parent = $element;
            $scope.tippyClass = $attrs.parent;
          }
        };
      })
      .directive('tippy', function() {
        return {
          controller: function ($attrs, $scope, $element) {
          console.log($attrs.id);
              tippy('.'+$scope.tippyClass, {
               position: 'bottom',
               animation: 'shift',
               arrow: true,
               interactive: true,
               arrowSize: 'big',
               distance: 20,
               html: $element[0],
               appendTo: $scope.parent[0]
              })
            }
          };
      })
      .controller('controller2', function($scope) {
        $scope.title = "Controller 2";
        $scope.cache = true;
      })
      .controller('controller1', function($scope) {
        $scope.title = "Controller 1";
        $scope.cache = false;
      });
    

    I recommend you to try to make the directive more generic and easy to use and maybe post a Github GIST so that others will be able to use Tippy easily in the future!!!!