33

I have some html data that I'm loading in from a json file.

I am displaying this html data by using ngSanitize in my app and using ng-bind-html.

Now I would like to convert any links in the json blob from the standard

  • <a href="some_link">link</a>

to:

  • <a ng-click="GotoLink('some_link','_system')">link</a>.

So I'm doing some regExp on the json file to convert the links, but for some reason however ng-bind-html is filtering out the ng-click in it's output, and I can't figure out why. Is it supposed to do this, and if so is it possible to disable this behavior?

Check out this jsFiddle for a demonstration: http://jsfiddle.net/7k8xJ/1/

Any ideas?

Squrler
  • 3,444
  • 8
  • 41
  • 62

3 Answers3

49

Ok, so the issue is that it isn't compiling the html you include (angular isn't parsing it to find directives and whatnot). Can't think of a way to make it to compile from within the controller, but you could create a directive that includes the content, and compiles it.

So you would change

<p ng-bind-html="name"></p>

to

<p compile="name"></p>

And then for the js:

var myApp = angular.module('myApp', ['ngSanitize']);
angular.module('myApp')
.directive('compile', ['$compile', function ($compile) {
  return function(scope, element, attrs) {
    scope.$watch(
      function(scope) {
        return scope.$eval(attrs.compile);
      },
      function(value) {
        element.html(value);
        $compile(element.contents())(scope);
      }
   )};
  }]).controller('MyCtrl', function($scope) {
    var str = 'hello http://www.cnn.com';
    var urlRegEx = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-]*)?\??(?:[\-\+=&;%@\.\w]*)#?(?:[\.\!\/\\\w]*))?)/g;
    result = str.replace(urlRegEx, "<a ng-click=\"GotoLink('$1',\'_system\')\">$1</a>");
    $scope.GotoLink = function() { alert(); }
    $scope.name = result;
});

Angular 1.2.12: http://jsfiddle.net/7k8xJ/4/

Angular 1.4.3: http://jsfiddle.net/5g6z58yy/ (same code as before, but some people were saying it doesn't work on 1.4.*)

dave
  • 62,300
  • 5
  • 72
  • 93
  • 1
    This works great, thanks! Just as a thought (and I'm not really clear on if I'm understanding $sce correctly, documentation is a bit unclear) but isn't is possible to whitelist browse-to so it will get outputted by ng-bind-html? – Squrler Mar 30 '14 at 15:21
  • 1
    This is not working for me in angular 1.4.3 throwing errors "Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!" – CGeorges Oct 15 '15 at 15:07
  • 1
    saw this solution in other answer as well.. but didn't work for me at 1.4.* – Ariful Haque Mar 22 '16 at 13:57
  • if this doesnt work for you, check that the method you want to call is indeed on your scope, depending on the scoping rules for the directive, it may be on the parents – Ben Taliadoros Aug 23 '18 at 14:40
3

I still faced some issue with the compile, as that was not fulfilling my requirement. So, there is this, a really nice and easy hack to work around this problem.

We replace the ng-click with onClick as onClick works. Then we write a javascript function and call that on onClick event. In the onClick function, we find the scope of the anchor tag and call that required function explicitly.

Below is how its done :)

Earlier,

<a id="myAnchor" ng-click="myControllerFunction()" href="something">

Now,

<a id="myAnchor" onClick="tempFunction()" href="something">

at the bottom or somewhere,

<script>
function tempFunction() {
 var scope = angular.element(document.getElementById('myAnchor')).scope();
  scope.$apply(function() {
    scope.myControllerFunction();
 });
}
</script>

This should work now. Hope that helps someone :)

For more info, see here.

Satys
  • 2,319
  • 1
  • 20
  • 26
2

Explicitly Trusting HTML With $sce When you want Angular to render model data as HTML with no questions asked, the $sce service is what you’ll need. $sce is the Strict Contextual Escaping service – a fancy name for a service that can wrap an HTML string with an object that tells the rest of Angular the HTML is trusted to render anywhere.

In the following version of the controller, the code asks for the $sce service and uses the service to transform the array of links into an array of trusted HTML objects using $sce.trustAsHtml.

app.controller('XYZController', function ($scope, $sce) {

$sce.trustAsHtml("<table><tr><td><a onclick='DeleteTaskType();' href='#workplan'>Delete</a></td></tr></table>");
Josip Ivic
  • 3,639
  • 9
  • 39
  • 57
user5740953
  • 169
  • 2
  • 16