9

I use the verions 0.14.2 of angular-ui-bootstrap. I was unable to display line returns in the popover. I use the popover-html directive, and a string such as

Limite inférieure<br>Limite supérieure

It gives the following error :

Lexer Error: Unexpected next character  at columns 41-41 [é] in expression [<div>Approchant des limites<br>Limite supérieure: 34:12<br>Limite inférieure: -34:12</div>].

I tried wrapping my string in a $sce.trustAsHtml call, but it didn't change a thing.

Here is a plunker http://plnkr.co/edit/3JSly1anPBUiGyqBcsD1

Yugo Amaryl
  • 1,249
  • 2
  • 15
  • 21

2 Answers2

20

Works for me using $sce.trustAsHtml as below.

Note: trustAsHtml tells Angular to trust that the HTML is safe, so should only be used if you do trust the HTML, i.e. its not user-supplied.

JS:

$scope.popoverContent = $sce.trustAsHtml('Line 1<br>Line2');

HTML:

<button popover-placement="right" uib-popover-html="popoverContent" type="button" class="btn btn-default">Popover</button>

Updated Plunker

Or if your content is dynamic and you need a function:

JS:

$scope.input = 'Line 1<br/>Line 2';

var trusted = {};

$scope.getPopoverContent = function(content) {
  return trusted[content] || (trusted[content] = $sce.trustAsHtml(content)); 
}

HTML:

<button popover-placement="right" uib-popover-html="getPopoverContent(input)" type="button" class="btn btn-default">Popover</button>

Plunker

(The reason for caching the value returned by trustAsHtml is that trustAsHtml always returns a new object so can cause an infinite $digest loop)

sheilak
  • 5,833
  • 7
  • 34
  • 43
  • Thank you. this works great, but I don't get the syntax. Why does this not work? $scope.getPopoverContent = function(input) { var content = input; return $sce.trustAsHtml(content)); } – iCediCe Mar 01 '16 at 14:02
  • It's because of this issue & workaround here https://github.com/angular/angular.js/issues/3932 – sheilak Mar 01 '16 at 14:11
  • this solution can lead to cross-site scripting if user-submitted input is displayed. – lcs.bdr Aug 24 '16 at 08:41
  • And also to memory leak, as the 'trusted' object will be inflated more and more – Maayan Hope Feb 24 '20 at 06:43
3

The accepted approach can easily lead to a cross-site scripting vulnerability in you application. You should really only use $sce.trustAsHtml if you explicitly trust the content that you want to display. The angular-bootstrap documentation also hints at that:

The user is responsible for ensuring the content is safe to put into the DOM!

An alternative and safer approach is to use uib-popover-template with a simple template in combination with ng-bind-html that automatically uses $sanitize to sanitize the HTML.

HTML

<p uib-popover-template="myPopoverTemplateUrl" 
   popover-trigger="mouseenter" 
   popover-placement="top" 
   popover-append-to-body="true">
        Show a Popover on Hover
</p>
<script type="text/ng-template" id="myPopoverTemplate.html">
    <div>
         <p ng-bind-html="popoverContent"></p>
    </div>
</script>

JS

$scope.myPopoverTemplateUrl = "myPopoverTemplate.html";
$scope.popoverContent = "This is HTML <b> And will be sanitized."

You also need to make sure to declare ngSanitize in your app and to include the angular-sanitize.js script. Please take a look at the updated plunker for reference.

Updated Plunker

lcs.bdr
  • 388
  • 1
  • 9