Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show tooltip only when the text is truncated in angular UI bootstrap directive

I want to show angular UI bootsrap tooltip only when the text is truncated. I tried the below code with custom directive

<div tooltip="{{value}}" tooltip-append-to-body="true" enable-truncate-tooltip>{{value}}</div>

.directive("enableTruncateTooltip", function () {
  return {
    restrict: 'A',
    link: function (scope, elem, attr) {
      elem.bind('mouseenter', function () {
        var $this = angular.element(this);

        if (this.offsetWidth >= this.scrollWidth) {
          angular.element('.tooltip').attr('hide-tooltip', true);
        }
      });
    }
  }
})

It works fine in angular-ui-bootstrap version 0.12.1. But later versions are not supporting this.

How can i achieve this same functionality in latest version of angular-ui-bootstrap?

Thanks in advance for your help.

like image 796
Sathya Avatar asked Feb 09 '16 15:02

Sathya


People also ask

How do I show tooltip conditionally?

We can use matTooltipDisabled property to show tooltip conditionally as shown below. We can bind a variable or we can pass a function to [matTooltipDisabled] to toggle the visibilty of material tooltip. Instead of that we can pass an expression to [matTooltip] to display or hide the tooltip as shown below.


2 Answers

TL;DR: Plunker Demo (using $watch) Old demo (using $timeout)

(The answer was updated to reflect a suggestion to use $watch instead of $timeout, thanks for the comment Michael Mish Kisilenko!)

First of all, change your angular-ui directives to the updated ones (prefix with 'uib-'):

<div uib-tooltip="{{value}}" show-tooltip-on-text-over-flow tooltip-enable="false">{{value}}</div>

And then use the following directive, which dynamically changes the angular-ui provided feature tooltip-enable (note that you should initialize the element with directive tooltip-enable="false" so the tooltip will be disabled if the text is not truncated:

myApp.directive("showTooltipOnTextOverflow", ["$timeout", function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var el = element[0];
      scope.$watch(function(){
        return el.scrollWidth;
      }, function() {
        var el = element[0];
        if (el.offsetWidth < el.scrollWidth) {
          //console.log('ellipsis is active for element', element);
          attrs.tooltipEnable = "true";
        } else {
          //console.log('ellipsis is NOT active for element', element);
        }
      });
      /*$timeout(function() {
        var el = element[0];
        if (el.offsetWidth < el.scrollWidth) {
          //console.log('ellipsis is active for element', element);
          attrs.tooltipEnable = "true";
        } else {
          //console.log('ellipsis is NOT active for element', element);
        }
      });*/
    }
  };
}]);

To truncate the text i'll use plain CSS:

span.truncated {
    width: 400px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
like image 123
Lulu Avatar answered Oct 31 '22 08:10

Lulu


Using watch as mentioned in answer posted by Lulu will bring performance down. It will add so many watchers as many cells grid has and these get evaluated in each digest cycle.

I modified his code to use mouseover approach - so the need of tooltip is evaluated in mouseover event only on particular cell:

myApp.directive("showTooltipOnTextOverflow", ["$timeout", function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      var el = element[0];

      if (angular.isObject(el)) {
        var evaluateTooltip = (event: JQueryEventObject, isOurEvent: boolean) => {
        // evaluate whether to enable tooltip
        attrs.tooltipEnable = el.offsetWidth < el.scrollWidth ? "true" : "false";

        if (isOurEvent !== true && attrs.tooltipEnable === "true") {
          // tooltip should be enabled, trigger mouseover again to trigger tooltip (current mouseover is already handled by tooltip with false value)
          // and mark it as our event to avoid its handling here
          element.trigger("mouseover", [true]);

          // revert tooltip enabling back to false to cover case when mouseover happens and tooltip should not be enabled
          scope.$applyAsync(() => {
          attrs.tooltipEnable = "false";
        });
      }
    };

    element.on("mouseover", evaluateTooltip);

    element.on("$destroy", () => {
      element.off("mouseover", evaluateTooltip);
    });
  }
});
like image 3
michal.jakubeczy Avatar answered Oct 31 '22 08:10

michal.jakubeczy