0

I want to truncate text after ng-repeat finished in angular.

I found a simple way is to use limitTo filter to limit text length. However, I want to turn text by it's actual width.

with reference of the page below, here is my code: Calling a function when ng-repeat has finished

html:

<div id="feedList"> 
    <div ng-repeat="feed in feeds | orderBy: '-date' "  feed-list-repeat-directive>
        <h4><span>{{ feed.title }}</span></h4>            
        <!-- some more contents here -->
    </div>
</div>

Javascript:

 var app = angular.module('anApp', []);
    app.controller('anCtrl', function($scope, $http) {  
        $http.get("data.php")   
        .success(function(response) {
            $scope.feeds = response.feeds;
        }); 
        $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {    

            // truncate text by width ##################################### 
            for(a=0; a<$('#feedList > div').length; a++){
                $thisH4 = $('#feedList > div').eq(a).children('h4');
                if($thisH4.width()<$thisH4.children('span').width()){                       
                    var txt = $thisH4.children('span').text();                  
                    while($thisH4.width()<$thisH4.children('span').width()){                
                        txt = txt.substr(0,txt.length-1);                       
                        $thisH4.children('span').text(txt+'...');
                    }
                };
            };
            //#######################################################   

        });
    })
    .directive('feedListRepeatDirective', function($timeout){
         return {
            restrict: 'A',
            link: function(scope, element, attrs) {         
                if (scope.$last){
                    $timeout(function () {
                        scope.$emit('ngRepeatFinished');            
                    });     
                };
             }
         }
    });

The problem is, when $scope.$on('ngRepeatFinished') runs, the data is not actually loaded to the dom, $thisH4.children('span').width() is returning 0,

It works only if I set a 0.4 sec delay by setTimeout(), but I think it is not sense making.

Is there any way to solve the problem or I better stick to limitTo filter?

thanks

Community
  • 1
  • 1
Wesleywai
  • 195
  • 11

1 Answers1

0

You don't need to wait for ng-repeat to finish and you're breaking the angular binding by setting the text element yourself. Why not create a directive on the h1 instead?

app.directive('limitHorizontal', ['$timeout', function($timeout) {
    return {
        restrict: 'A',
        template: '<h1>{{header}}</h1>',
        replace: true,
        scope: {
            rawHeader: '&limitHorizontal'
        },
        link: function(scope, element, attributes) {
            var suffix = "...";
            scope.header = scope.rawHeader();

            // Work out the % that is over the limit
            var overflowPercentage = function() {
                return (element[0].scrollWidth - element[0].clientWidth)/element[0].scrollWidth;
            };

            var addSuffix = function() {
                // Wrapped in a timeout to queue it for the next digest cycle
                $timeout(function() {
                    var overflow = overflowPercentage();
                    if (overflow) {
                        scope.header += suffix;
                        limitContent();
                    }
                });
            };

            var limitContent = function() {
                // Wrapped in a timeout to queue it for the next digest cycle
                $timeout(function() {
                    var overflow = overflowPercentage();
                    if (overflow) {
                    newLength = scope.rawHeader().length - Math.ceil(overflow * scope.header.length);
                    scope.header = scope.rawHeader().substring(0, newLength) + suffix;
                    }
                });
            };

            addSuffix();
        }
    };
}]);

with markup:

    <div data-ng-repeat="header in headers">
        <h1 class="short-header" data-limit-horizontal="header"></h1>
    </div>

See plunker

logee
  • 5,017
  • 1
  • 26
  • 34
  • Hi, It works fine when I am playing around the plunker page. But I don't know why it do not works on my actual page. when I put alert(element[0].clientWidth+" : "+element[0].scrollWidth); in the function overflowPercentage, it alert "XXX : 150" on plunker, but it alert "0 : 0" on my page. – Wesleywai Sep 11 '15 at 08:27
  • Is it in a `$timeout`? The reason I put it in a `$timeout` with no time is just to queue it for then next digest cycle, essentially waiting for the DOM to render so that I can get the widths – logee Sep 13 '15 at 03:38
  • not in $timeout, but in var overflowPercentage = function(){...} both element[0].scrollWidth and element[0].clientWidth is returning 0 my actual page. – Wesleywai Sep 14 '15 at 05:53
  • I mean is your call to `overflowPercentage` wrapped in a `$timeout`? Would you be able to product a plunker that shows your problem? – logee Sep 14 '15 at 06:21