Kunal Vashist
Kunal Vashist

Reputation: 2471

Angular js ellipsis

Is there any way where we can use angular js to substring the string and add the ellipsis at the end while ignoring the anchor tag if it is coming inside the substring?

For example, my text is:

Lorem Ipsum has been the industry's standard dummy text ever since the 1500s when an unknown printer took a galley of type and scrambled it to make a type specimen book.

I can only show the text up to 70 characters after that ellipsis.

In this case, from "55 - 100 approx" is anchor link, substring chips the string from 0,70 and create a bad string with broken anchor link.

On HTML, I am using:

> data-ng-bind-html

to parse the Substring.

How can we ignore < a href="something.html" > < /a > Tags inside the string and substring other content?

Don't want to use CSS as content can be of any length.

Filter used:

filter('customEllipsis', function() {
        return function(input, number) {
            if (input) {
                return input.length > number ? input.substring(0, number) + '...' : input;
            }
        };
    });

Upvotes: 1

Views: 407

Answers (3)

Robby Cornelissen
Robby Cornelissen

Reputation: 97130

Here is a solution that:

  1. Converts the HTML content to a DOM document
  2. Performs a depth-first traversal of the document
  3. Evaluates all text nodes, cuts off after the maximum length has been reached, and adds the ellipsis
  4. Discards remaining nodes
  5. Serializes the result back to HTML

The snippet below contains the complete implementation. It ends with an example in which the example string
Click <a href="http://stackoverflow.com">this absolutely <b>ah-mah-zing</b> link</a> to access Stackoverflow.
gets limited to 20, 25, 30, 35, 40, 45 and 50 characters respectively.

Run the code snippet to see the results.

function limit(string, maxLength) {
  let visit = function(node) {
    if (count < maxLength) {
      if (node.nodeType === Node.TEXT_NODE) {
        let left = maxLength - count;
        let length = node.nodeValue.length;

        if (length > left) {
          node.nodeValue = node.nodeValue.substring(0, left) + '...';
          count += left;
        } else {
          count += length;
        }
      } else {   
        for (let childNode of Array.from(node.childNodes)) {
          visit(childNode);
        }
      }
    } else {
      node.remove();
    }

    return node;
  };
  let dom = new DOMParser().parseFromString(string, "text/html");
  let tree = dom.body;
  let count = 0;

  return visit(tree).innerHTML;
}

let string = 'Click <a href="http://stackoverflow.com">this absolutely <b>ah-mah-zing</b> link</a> to access Stackoverflow.';

document.getElementById('container').innerHTML = [20, 25, 30, 35, 40, 45, 50]
        .map(maxLength => limit(string, maxLength))
        .join('<br>');
<div id="container"></div>

Advantages

  • It preserves all relevant tags, even nested tags
  • It's precise because the HTML tags and attributes are not taken into account to determine how many characters to display.

Disadvantages

  • Performance might not be stellar, although there's still room for optimization (e.g. the serializing back to HTML can be skipped, the DOMParser instance can be shared, etc.)

Upvotes: 0

Kursad Gulseven
Kursad Gulseven

Reputation: 2008

Use Angular sanitizer to parse html. See this jsbin for an example of usage.

app.filter('customEllipsis', function($sce) {
  return function(input, number) {
    if (input) {
      input = input.length > number ? input.substring(0, number) + '...' : input;
      input = $sce.trustAsHtml(input);
      return input;
    }
  };
});

Upvotes: 1

xkeshav
xkeshav

Reputation: 54016

You can use Angular's built-in filter limitTo

Upvotes: 0

Related Questions