angularJS: dotdotdot for overflow text and performance

All we need is an easy explanation of the problem, so here it is.

I’m new to angularJS and maybe have written something bad…

but how could i right implement this plugin: https://github.com/BeSite/jQuery.dotdotdot

on my table?

now with my code my edit form and table is really not too fast… really too slow… What have I done wrong?

directive:

.directive('dotdotdot', function(){
        return {
            restrict: 'A',
            link: function(scope, element, attributes) {
                scope.$watch(function() {
                    element.dotdotdot({watch: true, wrap: 'letter'});
                });
            }
        }
    });

and table:

<table id="articles" class="table table-striped articles-table">
  <thead>
    <tr class="table-row">
      <th data-ng-click="predicate = 'Date'; reverse=!reverse">Date<i ng-class="{'arrow-down' : (reverse && predicate==='Date') || (predicate!=='Date'), 'arrow-up' : !reverse && predicate==='Date'}"></i></th>
      <th data-ng-click="predicate = 'Title'; reverse=!reverse">Title<i ng-class="{'arrow-down' : (reverse && predicate==='Title') || (predicate!=='Title'), 'arrow-up' : !reverse && predicate==='Title'}"></i></th>
      <th data-sorter="false">article</th>
      <th data-sorter="false"></th>
      <th data-sorter="false"></th>
    </tr>
  </thead>
  <tbody>
    <tr data-ng-repeat="article in articles | orderBy:predicate:reverse" data-id="{{article.Id}}" class="table-row">                  
      <td class="text-nowrap">
        <div class="articles-cell">
          {{article.Date}}
        </div>                    
      </td>
      <td>
        <div class="articles-cell article-text-area" dotdotdot>                      
          {{article.Title}}
        </div>
      </td>
      <td>
        <div class="articles-cell">
          <a href="javascript:void(0)" rel="nofollow noreferrer noopener" data-ng-click="showarticle(article)" data-toggle="modal" data-target="#new-article" class="action">
            <img data-ng-src="{{article.Photo}}" data-err-src="images/no_photo.png" class="article-img img-rounded img-responsive" alt="article" />
          </a>
        </div>
      </td>
      <td>
        <div class="articles-cell" dotdotdot>
          <div class="content" data-ng-bind-html="article.Content" class="articles-row" ></div>
        </div>
      </td>
      <td class="crud-arr">
      </td>
    </tr>
  </tbody>
</table>

even if i rewrite it via binding’s – it’s to slow…
what i do wrong?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

As @pankajparkar noted in comments, this really shouldn’t be maintained in a $watch. Doing so executes the element.dotdotdot() configuration call several times in any given session–for example every time a key is pressed or the mouse is clicked. Part of the slowdown could be the plugin itself and how it manages the watching it does, but aside from that you should see improvement by simply removing the $watch:

.directive('dotdotdot', function(){
    return {
        restrict: 'A',
        link: function(scope, element, attributes) {
            element.dotdotdot({watch: true, wrap: 'letter'});
        }
    }
});

Method 2

Template

<li ng-repeat="movie in movies">
    <div dma-dotdotdot>{{movie.title}}</div>
</li>

Directive

(function () {
    'use strict';

    angular.module('dma.common').directive('dmaDotDotDot', [
        function dmaDotDotDot() {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    scope.$evalAsync(function () {
                        element.dotdotdot({
                            wrap: 'letter'
                        });
                    });
                }
            };
        }
    ]);
}());

I tested ng-bind and it doesn’t seem to work properly for me. ng-bind hides the content, then fires the dotdotdot(), then compiles the content (Which doesn’t work).

Though this should work—Much better solution than scope.$watch. And I believe it preforms more consistently than the solutions listed without $evalAsync().

See https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$evalAsync for more information regarding when it fires.

Method 3

I had this same problem and ended up just applying a class "dotdotdot" to all elements that I wanted the jquery.dotdotdot thing to run on, and then manually calling $('.dotdotdot').dotdotdot() whenever those element updated. You have to be careful to not use a $watch or anything like that or you’ll just have the same issue as if you used the directive. Not a pretty fix, but it is efficient.

Had to do this, because removing the $watch in the directive has weird side effects if you are using rawHtml binding or custom filters on the element in question.

Method 4

Here’s my attempt:

  • Adds an expression to the $watch call to improve performance
  • Removes { watch: true } option which needlessly polls

Directive:

app.directive('dotdotdot', ['$timeout', function($timeout) {
    return {
        restrict: 'A',
        link: function(scope, element, attributes) {

            scope.$watch(attributes.dotdotdot, function() {

                // Wait for DOM to render
                $timeout(function() {
                    element.dotdotdot();
                }, 400);
            });
        }
    }
}]);

Template:

<div dotdotdot='article.Title'>                      
      {{article.Title}}
</div>

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply