How do I create an AngularJS tooltip directive with a compiled template?

29,487

Solution 1

Here're the blueprints of how you could create a tooltip according to your requirements (or modify/encorporate this with ui-bootstrap's tooltip).

app.directive("myTooltipTemplate", function($compile){
  var contentContainer;
  return {
    restrict: "A",
    scope: {
      myTooltipScope: "="
    },
    link: function(scope, element, attrs, ctrl, linker){
      var templateUrl = attrs.myTooltipTemplate;

      element.append("<div ng-include='\"" + templateUrl + "\"'></div>");
      var toolTipScope = scope.$new(true);
      angular.extend(toolTipScope, scope.myTooltipScope);
      $compile(element.contents())(toolTipScope);
    }
  };

});

This, of course, doesn't have any of the actual tooltip functionality, like popup, placement, etc... - it just appends the compiled template to whatever the element that this directive applies to.

Plunker

Changed plunker with closer-to-tooltip behavior;

Solution 2

I was able to just copy and override the directive for the tooltip-html-unsafe

angular.module( 'ui.bootstrap.tooltip')
.directive( 'tooltipSpecialPopup', function () {
    return {
     restrict: 'EA',
     replace: true,
     scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
     templateUrl: 'tooltip.tpl.html'
  };
})

.directive( 'tooltipSpecial', [ '$tooltip', function ( $tooltip ) {
     return $tooltip( 'tooltipSpecial', 'tooltip', 'mouseenter' );
 }]);

I just changed the unsafe bit to special in the directive name and changed the template.

Here's a Plunker

Solution 3

I found this question searching for a classic tooltip implementation in AngularJS, jQuery (and other libraries) free.

I have built the following directive if anyone is searching for one:

app.directive('tooltip', function($sce, $compile) {
    return {
        restrict: 'A',
        scope: {
            content: '=tooltipContent'
        },
        link: function(scope, element, attributes) {

            /* Attributes */

            scope.displayTooltip = false;

            /* Methods */

            scope.updateTooltipPosition = function(top, left) {
                tooltip.css({
                    top: top + 'px',
                    left: left + 'px',
                });
            };

            scope.getSafeContent = function(content) {
                return $sce.trustAsHtml(content);
            };

            /* Bootstrap */

            var tooltip = angular.element(
                '<div ng-show="displayTooltip" class="tooltip">\
                    <span ng-bind-html="getSafeContent(content)"></span>\
                </div>'
            );

            angular.element(document.querySelector('body')).append(tooltip);

            /* Bindings */

            element.on('mouseenter', function(event) {
                scope.displayTooltip = true;
                scope.$digest();
            });

            element.on('mousemove', function(event) {
                scope.updateTooltipPosition(event.clientY + 15, event.clientX + 15);
            });

            element.on('mouseleave', function() {
                scope.displayTooltip = false;
                scope.$digest();
            });

            /* Compile */

            $compile(tooltip)(scope);
        }
    };
});

You can test it here: http://jsfiddle.net/m4sr9jmn/2/

Hope it will help !

Share:
29,487
Aviad P.
Author by

Aviad P.

Likes programming C#, F#, TypeScript, and playing Go. Focusing on Angular.

Updated on July 09, 2022

Comments

  • Aviad P.
    Aviad P. almost 2 years

    I've searched the internet long and hard and found no straight answer. My question is simple, I want to have something like this in my markup:

    <div my-tooltip-template="'mytt.tpl.html'" my-tooltip-scope="myDataItem">Some text...</div>
    

    EDIT: Where myDataItem is a scope variable which contains my data object, and with a template which might look like:

    <h1>{{dataItem.title}}</h1>
    <span>{{dataItem.description}}</span>
    

    And I want to have that template compiled with the a scope which contains myDataItem as dataItem and displayed as a tooltip. As far as I could tell by experimenting with ui-bootstrap tooltip module, the way to inject html into a tooltip is by using the directive tooltip-html-unsafe but the html injected doesn't get compiled, i.e., angular expressions are not evaluated, directives are not expanded, etc.

    How do I go about creating a directive for this? I want a lean result, I don't want to have to include jQuery or any other library, just AngularJS and ui-bootstrap.

    Thanks a lot!