esgy
esgy

Reputation: 392

How to fix "10 $digest() iterations reached. Aborting!" error in Angular 1.2 filter?

I've created a filter in AngularJS 1.2 that uses the ShowdownJS to parse Markdown content into HTML:

App.filter('markdown', function( $sce ) {
    var converter = new Showdown.converter();
    return function (value) {
        var html = converter.makeHtml(value);
        return $sce.trustAsHtml(html);
    };
});

The binding in the templates is done with ng-bind-html. This one receives to final HTML content so it's mandatory to show the content:

<div ng-bind-html="post.content | markdown"></div>

The filter works but I get this error in console because it returns the $sce service and it SHOULD return just the parsed HTML string.

10 $digest() iterations reached. Aborting!

How can I avoid this in a filter? I could not find any method that can can extract the escaped html from the $sce service.

EDIT: if I disable the sanitize service in the config I don't get this error even if the code remains exactly the same.

$sceProvider.enabled(false);

Upvotes: 4

Views: 6893

Answers (4)

Brett Pennings
Brett Pennings

Reputation: 1499

When I had this error, I was accidentally using a filter on an object instead of a string.

Upvotes: 0

Liviu T.
Liviu T.

Reputation: 23664

Ok after some investigation I found that the problem is instances. Every time your filter fires you return another instance. Then the ng-bind-html watcher fires infinitely.

Demo

I added a cache of all trusted values:

app.filter('markdown', ['$sce', function( $sce ) {
    var converter = new Showdown.converter();
    var converted = {};

    return function (value) {
      if(converted.hasOwnProperty(value)) {
        return converted[value];
      }

      var html = converter.makeHtml(value);
      var trusted = converted[value] = $sce.trustAsHtml(html);
      return trusted;
    };
}]); 

Upvotes: 3

peterorum
peterorum

Reputation: 1421

try

return $sce.trustAsHtml(html).toString();

Upvotes: 0

Jason Goemaat
Jason Goemaat

Reputation: 29214

I think it has something to do with ngBindHtmlDirective watching it and calling $sce.getTrustedHtml on the value. You can get around it by avoiding $sce and using your own directive (plnkr):

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})

Upvotes: 1

Related Questions