3

I am currently working with ng-bind-html. Basically, what I am trying to do is, when I post a blog, the blog contains links and other styling. So when I am trying to show the list of blogs, I am using ng-bing-html like this:

<p ng-bind-html="blog.blogContent"></p>

which works fine.

But in addition, I try to truncate the blog and show only few paragraphs with view more option by passing a custom filter. But when I pass the filter I get the following:

<p ng-bind-html="blog.blogContent | Truncate"></p>

Error: [$sanitize:badparse] The sanitizer was unable to parse the
following block of html: <a href="https:.......

My Filter looks like this:

return function (text, length, end) {
    if (text !== undefined) {
      if (isNaN(length)) {
        length = 450;
      }

      if (end === undefined) {
        end = ".......";
      }

      if (text.length <= length || text.length - end.length <= length) {
        return text;
      } else {
        return String(text).substring(0, length - end.length) + end;
      }
    }
Rana_S
  • 1,520
  • 2
  • 23
  • 39
  • 1
    Robinson - It appears your filter is running first and truncating the HTML. the ng-bind-html is then attempting to parse an invalid HTML string giving you the error. –  Sep 11 '15 at 02:37
  • You could modify your filter to use the code posted by Minouris in this solution and see if that does the trick. http://stackoverflow.com/questions/3822233/javascript-truncate-html-text –  Sep 11 '15 at 02:48
  • Thanks, I will @user1! – Rana_S Sep 11 '15 at 02:49

2 Answers2

1

You can solve this using custom directives and filters. try this one: https://stackoverflow.com/a/45076560/6816707

0

I used the solution posted by Minouris in this post (Javascript truncate HTML text) and adapted it into an AngularJS filter. It seems to work pretty well. The filter is

angular.module('plunker').filter('Truncate', function() {
  return function(text, length, end) {
       if (text !== undefined) {
      if (isNaN(length)) {
        length = 20;
      }

      if (end === undefined) {
        end = ".......";
      }

      if (text.length <= length || text.length - end.length <= length) {
        return text;
      }

    var truncated = text.substring(0, length);
    // Remove line breaks and surrounding whitespace
    truncated = truncated.replace(/(\r\n|\n|\r)/gm,"").trim();
    // If the text ends with an incomplete start tag, trim it off
    truncated = truncated.replace(/<(\w*)(?:(?:\s\w+(?:={0,1}(["']{0,1})\w*\2{0,1})))*$/g, '');
    // If the text ends with a truncated end tag, fix it.
    var truncatedEndTagExpr = /<\/((?:\w*))$/g;
    var truncatedEndTagMatch = truncatedEndTagExpr.exec(truncated);
    if (truncatedEndTagMatch != null) {
        var truncatedEndTag = truncatedEndTagMatch[1];
        // Check to see if there's an identifiable tag in the end tag
        if (truncatedEndTag.length > 0) {
            // If so, find the start tag, and close it
            var startTagExpr = new RegExp(
                "<(" + truncatedEndTag + "\\w?)(?:(?:\\s\\w+(?:=([\"\'])\\w*\\2)))*>");
            var testString = truncated;
            var startTagMatch = startTagExpr.exec(testString);

            var startTag = null;
            while (startTagMatch != null) {
                startTag = startTagMatch[1];
                testString = testString.replace(startTagExpr, '');
                startTagMatch = startTagExpr.exec(testString);
            }
            if (startTag != null) {
                truncated = truncated.replace(truncatedEndTagExpr, '</' + startTag + '>');
            }
        } else {
            // Otherwise, cull off the broken end tag
            truncated = truncated.replace(truncatedEndTagExpr, '');
        }
    }
    // Now the tricky part. Reverse the text, and look for opening tags. For each opening tag,
    //  check to see that he closing tag before it is for that tag. If not, append a closing tag.
    var testString = reverseHtml(truncated);
    var reverseTagOpenExpr = /<(?:(["'])\w*\1=\w+ )*(\w*)>/;
    var tagMatch = reverseTagOpenExpr.exec(testString);
    while (tagMatch != null) {
        var tag = tagMatch[0];
        var tagName = tagMatch[2];
        var startPos = tagMatch.index;
        var endPos = startPos + tag.length;
        var fragment = testString.substring(0, endPos);
        // Test to see if an end tag is found in the fragment. If not, append one to the end
        //  of the truncated HTML, thus closing the last unclosed tag
        if (!new RegExp("<" + tagName + "\/>").test(fragment)) {
            truncated += '</' + reverseHtml(tagName) + '>';
        }
        // Get rid of the already tested fragment
        testString = testString.replace(fragment, '');
        // Get another tag to test
        tagMatch = reverseTagOpenExpr.exec(testString);
    }
    return truncated;
  }
  }

  function reverseHtml(str) {
    var ph = String.fromCharCode(206);
    var result = str.split('').reverse().join('');
    while (result.indexOf('<') > -1) {
        result = result.replace('<',ph);
    }
    while (result.indexOf('>') > -1) {
        result = result.replace('>', '<');
    }
    while (result.indexOf(ph) > -1) {
        result = result.replace(ph, '>');
    }
    return result;
}
  });

Working plunkr: http://plnkr.co/edit/oCwmGyBXB26omocT2q9m?p=preview

I havent tested the above solution and you may run into issues with more complicated HTML strings. May I suggest using a Jquery library like https://github.com/pathable/truncate to be safe?

Community
  • 1
  • 1