Summer Developer
Summer Developer

Reputation: 2086

Angular Bootstrap Tooltip Dynamic Content

I am making a cart application in Angular using Angular Bootstrap.

When hovering over the cart icon a tooltip should appear. The tooltip's content should change based on if the item is already in the cart or not.

So, here is the html:

<h3><i class="fa fa-shopping-basket" ng-click="add2Cart(item.Name)" tooltip-placement="right" uib-tooltip-html="itemtooltiptext(item.Name)" aria-hidden="true"></i></h3>

Basically, in order to check if the item is already in the cart, I want the tooltip text to resolve from a function. My understanding from the documentation is this is supported as long as the HTML is trusted.

It says,

uib-tooltip-html $ - Takes an expression that evaluates to an HTML string. Note that this HTML is not compiled. If compilation is required, please use the uib-tooltip-template attribute option instead. The user is responsible for ensuring the content is safe to put into the DOM!

So my itemtooltiptext() function is...

  $scope.itemtooltiptext = function(name) {
  if (localStorage.getItem("cart") === null) {
    return $sce.trustAsHtml("Add " + name + " to Cart!");
  } else {
    var cart = JSON.parse(localStorage.getItem("cart"));
    for (var i = 0; i < cart.length; i++) {
      if (cart[i] == name) {
        console.log("already in cart");
        return $sce.trustAsHtml(name + "already in Cart!");
      }
    }
    return $sce.trustAsHtml("Add " + name + " to Cart!");
  }
}   

This results in an

Infinite $digest Loop Error

As detailed here: https://stackoverflow.com/a/19370032

But the problem is I need it to come from a function with the various conditions? So should I be using a template? I don't understand how that would work any better because I still need dynamic text served from the template... so what is the solution?

Thank you.

Upvotes: 5

Views: 11414

Answers (2)

Joules
Joules

Reputation: 3

I ran into this infinite digest cycle issue where I needed a dynamic tooltip... it caused angular to recalculate it every time as a new value (even though it was the same). I created a function to cache the computed value like so:

$ctrl.myObj = {
    Title: 'my title',
    A: 'first part of dynamic toolip',
    B: 'second part of dynamic tooltip',
    C: 'some other value',
    getTooltip: function () {
        // cache the tooltip
        var obj = this;
        var tooltip = '<strong>A: </strong>' + obj.A + '<br><strong>B: </strong>' + obj.B;
        var $tooltip = {
            raw: tooltip,
            trusted: $sce.trustAsHtml(tooltip)
        };
        if (!obj.$tooltip) obj.$tooltip = $tooltip;
        else if (obj.$tooltip.raw !== tooltip) obj.$tooltip = $tooltip;
        return obj.$tooltip;
    }
};

Then in the html, I accessed it like this:

<input type="text" ng-model="$ctrl.myObj.C"
    uib-tooltip-html="$ctrl.myObj.getTooltip().trusted">

Upvotes: 0

svarog
svarog

Reputation: 9839

This is not how you use uib-tooltip-html, apparently it causes an infinite digest loop, fortunately the demo plunk shows you how to do it.

You need to get/calculate your html, bind to some scope variable and bind it into uib-tooltip-html

js

$scope.itemtooltiptext = function() {
    $scope.htmlTooltip = $sce.trustAsHtml('I\'ve been made <b>bold</b>!');
};
$scope.itemtooltiptext();

html

<button uib-tooltip-html="htmlTooltip" class="btn btn-default">Tooltip</button>

If you still want to bind a function to your tooltip, you can do like so

<button uib-tooltip="{{itemtooltiptext()}}" class="btn btn-default">Tooltip</button>

Note that this approache will have the function invoked every digest cycle.

Upvotes: 3

Related Questions