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 piled. If pilation 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:
But the problem is I need it to e 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.
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 piled. If pilation 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./a/19370032
But the problem is I need it to e 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.
Share Improve this question edited May 23, 2017 at 11:54 CommunityBot 11 silver badge asked Feb 5, 2017 at 20:54 Summer DeveloperSummer Developer 2,0868 gold badges35 silver badges68 bronze badges 1- can you make up a plunk? – svarog Commented Feb 6, 2017 at 10:00
2 Answers
Reset to default 3This 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.
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 puted 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">