Reputation: 2086
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
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
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