1

I need to (dynamically) render text inside fixed-length buttons in a ng-repeat block. I would like to get DOM rendered text width (to be able to truncate it, and add an ellipsis entity...).
This is my html:

 <span ng-repeat="(key, item) in players" limit-text-length max-len="100">
    <div class="btn">
      <div id="player-{{key}}">{{item.name}}</div>
    </div>
 </span>

This is my current directive:

app.directive('limitTextLength', function() {
  return function(scope, element, attrs) {
  var maxLen = attrs.maxLen;
  var el = element.find​("[id^=player-]"); // <-- THIS DOESN'T WORK...
  if (el.width() > maxLen) { // check text is not too wide
    while (el.width() > maxLen) {
      var nameTruncated = el.html();
      nameTruncated = nameTruncated.substring(0, nameTruncated.length - 1);
      el.html(nameTruncated);
    }
    el.append('&hellip;');
  }
};

Any suggestion?

4
  • I'm not sure but maybe you could try to put var el = element.find​("[id^=player-]"); [...] inside $timeout() function. Then it should be run after text render. Commented May 31, 2014 at 22:37
  • @ExpertSystem's answer should solve this but did you consider edge case where adding ellipsis would change the width and make it more than maxLen? Commented May 31, 2014 at 23:11
  • @czwek: yes, this is the right solution... See ExpertSystem answer... Commented Jun 1, 2014 at 9:23
  • @amitamb: yes, maxLen should take into account the ellipsis width... Commented Jun 1, 2014 at 9:24

1 Answer 1

3

element.find("[id^=player-]") won't work without jQuery, because Angular's jqLite's find() is limited to lookups by tag name (according to the docs).

You could use the native querySelector() method, which has good support in browsers:

//var el = element.find("[id^=player-]");
var el = angular.element(element[0].querySelector('[id^="player-"'));

Of course, without jQuery the .width() method won't be available, but if you do use jQuery, your selector should work fine.


There is also a typo: var maxLen = attrs.len; should be var maxLen = attrs.maxLen;


That said, the main problem is that the element's actual width is determined after being rendered (which hasn't happened at the time you check). You could make sure you check after the element has been rendered, by wrapping the relevant code inside $timeout.
Your directive could be modified like this (assuming jQuery is included):

app.directive('limitTextLength', function ($timeout) {
    return function(scope, element, attrs) {
        var maxLen = attrs.maxLen;
        var el = element.find("[id^=player-]");
        $timeout(function () {
            if (el.width() > maxLen) { // check text is not too wide
                while (el.width() > maxLen) {
                    console.log(el.width());
                    var nameTruncated = el.html();
                    nameTruncated = nameTruncated.substring(0, nameTruncated.length - 1);
                    el.html(nameTruncated);
                }
                el.append('&hellip;');
            }
        });
    };
});

See, also, this short demo.


BTW, if it is just for the ellipsis, you could use CSS3's text-overflow property.

Sign up to request clarification or add additional context in comments.

3 Comments

This is a perfect answer. I knew element find needs a full jQuery; I could obtain the same result using jqLite alternatives, but I did not mention it in the answer because it's not as straightforward as jQuery... My compliments for noticing it. I did suppose the problem was with rendering not completed when directive executes. My compliments for solving it. I didn't think about text-overflow, but my main goal was to gain experience with Angular directives... Thanks for your answer.
Just for future reference: I had a minor issue with my html: I had to use a span instead of a div (<span id="player-{{key}}">{{item.name}}</span>), otherwise width was related to the text container, instead of text itself...
@MarcoS: I have replaced it with a <span> in my demo, but I assumed you were applying some CSS to the same end in your code. If not, then indeed a <div> will never change it's size based on text-content (and it will eventually crash your browser (because of the infinite while loop).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.