7

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.

2 Answers 2

8

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;
}
Sign up to request clarification or add additional context in comments.

7 Comments

A better and more flexible solution would probably to loose the "timeout" and use scope.$watch over the element's scrollWidth
@MichaelMishKisilenko solution is perfect, just don't forget to use it the right way with the property
@Sathya: We need to implement the same thing. We are using cell template and unable to display "uib-tooltip" in the first place. Is "uib-tooltip" not compatible with celltemplate or do you have any workaround for the same?
In "cell" you actually mean cellphone (i.e. mobile)?
Hi @Lulu: No, by celltemplate I meant html template (external html file) which is used to display cell contents in Angular ui-grid datatable - link. Celltemplate is a custom template for each cell in this column. And we are trying to use the "uib-tooltip" inside the celltemplate,
|
3

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);
    });
  }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.