Yoav
Yoav

Reputation: 3386

Bootstrap tooltip from dynamic HTML not working

I have an HTML page that part of it is generated using HTML injection from a typescript angularjs controller using $sce and ng-bind-html.
My problem is that the bootstrap tooltip style isn't applied and I only get the simple built in yellow tooltip.
My controller function that generates the HTML (not sure if it's relevant but note the comment next to the console.log section):

public renderHtml = () => {
this.test = '<span style="text-decoration:underline" data-toggle="tooltip" data-placement="top" title="Tooltip on top">my team</span>';
console.log(this.test); // this line is logged 6 times with the same value on each page refresh

return this.$sce.trustAsHtml(this.test);
}

The HTML (I've added the exact same HTML snippet directly to the page and it works fine):

<!--bootstrap tooltip doesn't show-->
<div class="row margin-25" ng-bind-html="cdc.renderHtml()"></div>

<div>
<!--bootstrap tooltip works-->
<span style="text-decoration:underline" data-toggle="tooltip" data-placement="top" title="Tooltip on top">my team</span>
</div>

Here is the outcome (not working on left): tooltips

Upvotes: 0

Views: 1588

Answers (2)

Stepan Kasyanenko
Stepan Kasyanenko

Reputation: 3186

As per documentation:

Opt-in functionality

For performance reasons, the Tooltip and Popover data-apis are opt-in, meaning you must initialize them yourself.

Example with your approach on jsfiddle:

angular.module('ExampleApp', [])
  .controller('ExampleController', function($sce) {
    this.renderHTML = () => {
      return $sce.trustAsHtml('<span style="text-decoration:underline" data-toggle="tooltip" data-placement="bottom" title="Tooltip on top">my team</span>');
    };
  });
$(document).ready(function() {
  $('span').tooltip();
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<div ng-app="ExampleApp">
  <div ng-controller="ExampleController as vm">
    <div ng-bind-html="vm.renderHTML()"></div>
    <span style="text-decoration:underline" data-toggle="tooltip" data-placement="right" title="Tooltip on top">my team</span>
  </div>
</div>

Better solution is use directive:

angular.module('ExampleApp', [])
  .controller('ExampleController', function($sce) {})
  .directive("title", function($timeout) {
    return {
      link: function(scope, element) {
        $timeout(function() {
          $(element).tooltip()
        }, 0);
      }
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<div ng-app="ExampleApp">
  <div ng-controller="ExampleController as vm">
    <div>
      <span style="text-decoration:underline" data-toggle="tooltip" data-placement="bottom" title="Tooltip on top">my team</span>
    </div>
    <span style="text-decoration:underline" data-toggle="tooltip" data-placement="right" title="Tooltip on top">my team</span>
  </div>
</div>

Upvotes: 1

Pjetr
Pjetr

Reputation: 1382

Bootstrap works with jQuery, meaning all interaction is called upon document.ready, when you add new content, jQuery doesn't know how to use this new content. There is a project that implements bootstrap the angular way: ng-bootstrap.

Instead of writing HTML in your code to add to the page, you should work using directives or components. I would recommend following the free course by codeschool, it explains how to use them, and why this is the angular way.

To simply get your tooltip to work, without doing it more in the angular way:

public renderHtml = () => {
  this.test = '<span style="text-decoration:underline" data-toggle="tooltip" data-placement="top" title="Tooltip on top">my team</span>';
  console.log(this.test); // this line is logged 6 times with the same value on each page refresh
  
  $timeout(function() {
    angular.element('[data-toggle="tooltip"]').tooltip(); // if you've added jQuery, angular.element simply uses jQuery
  }, 0); // timeout 0 means it'll run in the next $digest cycle.

  return this.$sce.trustAsHtml(this.test);
}

Upvotes: 1

Related Questions