234

I have the following:

<div>{{modal.title}}</div>

Is there a way that I could limit the length of the string to say 20 characters?

And an even better question would be is there a way that I could change the string to be truncated and show ... at the end if it's more than 20 characters?

Andrew Sula
  • 939
  • 8
  • 24
Alan2
  • 23,493
  • 79
  • 256
  • 450

27 Answers27

510

Here is the simple one line fix without css.

{{ myString | limitTo: 20 }}{{myString.length > 20 ? '...' : ''}}
Govan
  • 7,751
  • 5
  • 26
  • 42
  • 79
    Simple and elegant. Instead of `'...'` you can also use the HTML entity for ellipsis: `'…'` – Tom Harrison Jan 21 '15 at 17:54
  • probably the most painless solution. Still keep in mind that filters are relatively heavy and this might have performance issues on huge ng-repeat list! :) – Cowwando Feb 28 '16 at 12:47
  • 1
    awesome! is there a way to cut after a number of lines, rather than after a number of characters? – axd Jun 28 '16 at 09:22
  • @axd You need to try that in css or write a directive to achieve that. – Govan Jun 28 '16 at 11:49
  • 1
    This is the best answer. The performance hit should be negligible with a reasonable number of ng-repeat. If you're bringing back hundred's of ng-repeat with content that needs to be truncated then might need to go back to drawing board. Nice answer, @Govan – erier Sep 21 '16 at 18:12
  • Please what if I want to apply a limit to the total length of two strings? – Ne AS Dec 05 '16 at 09:25
  • @Lig Please elaborate. Any example of what you require will be helpful. – Govan Dec 05 '16 at 13:25
  • @Govan lets say that I have $scope.string1 and $scope.string2. In the HTML I display {{string1}} {{string2}}. I want that the total of charatecters of the two string have a limit. How can I do that? – Ne AS Dec 05 '16 at 14:29
  • @Lig have to write custom filter for this. If you wish ask a separate question and post the link here. I ll answer that. – Govan Dec 06 '16 at 05:36
  • But this solution doesn't have support for word wise cut – shaikh Dec 06 '16 at 11:56
  • How can i do this with ng-bind-html ? – Usman Iqbal Dec 06 '17 at 13:33
349

Edit The latest version of AngularJSoffers limitTo filter.

You need a custom filter like this:

angular.module('ng').filter('cut', function () {
        return function (value, wordwise, max, tail) {
            if (!value) return '';

            max = parseInt(max, 10);
            if (!max) return value;
            if (value.length <= max) return value;

            value = value.substr(0, max);
            if (wordwise) {
                var lastspace = value.lastIndexOf(' ');
                if (lastspace !== -1) {
                  //Also remove . and , so its gives a cleaner result.
                  if (value.charAt(lastspace-1) === '.' || value.charAt(lastspace-1) === ',') {
                    lastspace = lastspace - 1;
                  }
                  value = value.substr(0, lastspace);
                }
            }

            return value + (tail || ' …');
        };
    });

Usage:

{{some_text | cut:true:100:' ...'}}

Options:

  • wordwise (boolean) - if true, cut only by words bounds,
  • max (integer) - max length of the text, cut to this number of chars,
  • tail (string, default: ' …') - add this string to the input string if the string was cut.

Another solution: http://ngmodules.org/modules/angularjs-truncate (by @Ehvince)

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
EpokK
  • 38,062
  • 9
  • 61
  • 69
  • 2
    There's an equivalent at angular-modules: http://ngmodules.org/modules/angularjs-truncate – Ehvince Aug 07 '13 at 15:16
  • angularjs-truncate isn't solution, but your IS solution. Thank you! Make it as module! – Anton Bessonov Apr 29 '14 at 19:48
  • @epokk There's a way to allow user to, after click on the three dots, show the complete uncut text? Like a "show more"? Thanks! – Thales P Dec 07 '14 at 19:23
  • this works fine when we use it like this {{post.post_content | cut:true:100:' ...'}} But fails when i use like this Because i am forced to use it with trusted html in my case – S Vinesh Apr 19 '15 at 13:22
  • The wordwise limit is a nice feature that doesnt seem to exist in the default "limitTo" – pdizz Jul 28 '15 at 20:25
  • Is there a simple way `filterTo` to make the string truncated at the first space after the position limit ? So it doesn't split at the middle of a word. – Ellone Dec 15 '15 at 09:07
  • I just wanted to improve this answer a bit, if the last word of the wrapping has a comma or dot at the end, it ends up with something like .... or ,... which I hate, so It can be improved by adding the following right after the lastspace != -1 if statement `if (value.charAt(lastspace-1) == '.' || value.charAt(lastspace-1) == ',') { lastspace = lastspace - 1; }` – JDDelgado Apr 11 '16 at 13:02
  • @EpokK: Thanks. how about adding `read more` link if cut happens – Moe Far Jun 17 '16 at 09:17
  • @ThalesP Of course this is an old question but to do something like that (click and show the text) I just put a ng-click="ctrl.cutting=!ctrl.cutting; ctrl.cut2 = ctrl.cutting ? 50 : 5000;" in my html element that contains the text and 2 variables vm.cutting = true; vm.cut2 = 50; on my controller. If I click on my text the limit will be 5000 instead of 50. – LiefLayer Sep 27 '19 at 14:10
  • @LiefLayer Hehehe, really old :) Tkx – Thales P Jul 15 '20 at 23:01
61

I know this is late, but in the latest version of angularjs (I'm using 1.2.16) the limitTo filter supports strings as well as arrays so you can limit the length of the string like this:

{{ "My String Is Too Long" | limitTo: 9 }}

which will output:

My String
slim
  • 2,545
  • 1
  • 24
  • 38
  • 9
    This solution is missing the "...". The result should be: "My String..." – Snæbjørn Sep 02 '14 at 13:37
  • I'm not seeing the ellipsis here: http://plnkr.co/edit/HyAejS2DY781bqcT0RgV?p=preview. Can you elaborate? – slim Sep 03 '14 at 14:52
  • 2
    What @Snæbjørn is saying is that the person who asked the question preferred a solution that inserts "..." at the end of the truncated string. Govan's answer does that. – Nahn Jan 09 '15 at 15:17
  • @Nahn thanks for pointing that out. I probably should have made a comment to EpokK's answer instead of another answer. – slim Jan 09 '15 at 17:23
52

You can simply add a css class to the div, and add a tool tip via angularjs so that trimmed text will be visible on mouse over.

<div class="trim-info" tooltip="{{modal.title}}">{{modal.title}}</div>

   .trim-info {
      max-width: 50px;
      display: inline-block;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;  
      line-height: 15px;
      position: relative;
   }
Sushrut
  • 1,541
  • 1
  • 12
  • 16
  • 4
    text-overflow: ellipsis, nice one. – Chris Russo May 14 '14 at 00:59
  • 4
    this technique, while awesome, prevents text from wrapping – Larry Aug 07 '14 at 12:58
  • This is the correct answer. My general rule is: "don't do in JavaScript that which can be done in CSS". – aidan Oct 22 '15 at 04:24
  • 4
    This only works for text with one line per paragraph. See for multiline https://css-tricks.com/line-clampin/ (not all browsers support that). – Robert Feb 04 '16 at 11:44
  • This also works if you are trying to limit the length of an array `ng-repeat`. – chakeda May 26 '16 at 15:21
  • Its a perfect css-pure solution for single line - wont work if you need multiple lines because of the 'white-space: nowrap; ' – Ignacio Vazquez Jan 24 '18 at 18:26
  • The line-height isn't necessary since you might be dealing with different sizes/heights of text. With the line-height in place you end up truncating the foot of the g or j or y – Robbie Smith Jun 13 '19 at 15:19
27

I had a similar problem, here is what i did:

{{ longString | limitTo: 20 }} {{longString.length < 20 ? '' : '...'}}
crc442
  • 607
  • 7
  • 13
22
< div >{{modal.title | limitTo:20}}...< / div>
Hiren
  • 12,720
  • 7
  • 52
  • 72
Thiago Araújo
  • 800
  • 9
  • 8
  • Simplest approach, yet functional. But it assumes that every title would have more than 20 characters and this, in some cases, may be unexpected. – Henrique M. Aug 31 '16 at 15:21
18

More elegant solution:

HTML:

<html ng-app="phoneCat">
  <body>
    {{ "AngularJS string limit example" | strLimit: 20 }}
  </body>
</html>

Angular Code:

 var phoneCat = angular.module('phoneCat', []);

 phoneCat.filter('strLimit', ['$filter', function($filter) {
   return function(input, limit) {
      if (! input) return;
      if (input.length <= limit) {
          return input;
      }

      return $filter('limitTo')(input, limit) + '...';
   };
}]);

Demo:

http://code-chunk.com/chunks/547bfb3f15aa1/str-limit-implementation-for-angularjs

Anam
  • 11,999
  • 9
  • 49
  • 63
  • Can I suggest adding a return in case the `input` value is dynamic? i.e. `if (!input) {return;}` Otherwise there will be JS console errors – mcranston18 Mar 25 '15 at 14:46
15

Since we need ellipsis only when the string length is over the limit, it seems more appropriate to add ellipsis by using ng-if than binding.

{{ longString | limitTo: 20 }}<span ng-if="longString.length > 20">&hellip;</span>
mnishiguchi
  • 2,051
  • 23
  • 17
11

The simplest solution I found for simply limiting the string length was {{ modal.title | slice:0:20 }}, and then borrowing from @Govan above you can use {{ modal.title.length > 20 ? '...' : ''}} to add the suspension points if the string is longer than 20, so the final result is simply:

{{ modal.title | slice:0:20 }}{{ modal.title.length > 20 ? '...' : ''}}

https://angular.io/docs/ts/latest/api/common/index/SlicePipe-pipe.html

maudulus
  • 10,627
  • 10
  • 78
  • 117
7

There is an option

.text {
            max-width: 140px;
            white-space: nowrap;
            overflow: hidden;
            padding: 5px;
            text-overflow: ellipsis;(...)
        }
<div class="text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi qui soluta labore! Facere nisi aperiam sequi dolores voluptatum delectus vel vero animi, commodi harum molestias deleniti, quasi nesciunt. Distinctio veniam minus ut vero rerum debitis placeat veritatis doloremque laborum optio, nemo quibusdam ad, sed cum quas maxime hic enim sint at quos cupiditate qui eius quam tempora. Ab sint in sunt consequuntur assumenda ratione voluptates dicta dolor aliquid at esse quaerat ea, veritatis reiciendis, labore repellendus rem optio debitis illum! Eos dignissimos, atque possimus, voluptatibus similique error. Perferendis error doloribus harum enim dolorem, suscipit unde vel, totam in quia mollitia.</div>
4

Here's a custom filter for truncating text. It's inspired by EpokK's solution but modified for my needs and tastes.

angular.module('app').filter('truncate', function () {

    return function (content, maxCharacters) {

        if (content == null) return "";

        content = "" + content;

        content = content.trim();

        if (content.length <= maxCharacters) return content;

        content = content.substring(0, maxCharacters);

        var lastSpace = content.lastIndexOf(" ");

        if (lastSpace > -1) content = content.substr(0, lastSpace);

        return content + '...';
    };
});

And here are the unit tests so you can see how it's supposed to behave:

describe('truncate filter', function () {

    var truncate,
        unfiltered = " one two three four ";

    beforeEach(function () {

        module('app');

        inject(function ($filter) {

            truncate = $filter('truncate');
        });
    });

    it('should be defined', function () {

        expect(truncate).to.be.ok;
    });

    it('should return an object', function () {

        expect(truncate(unfiltered, 0)).to.be.ok;
    });

    it('should remove leading and trailing whitespace', function () {

        expect(truncate(unfiltered, 100)).to.equal("one two three four");
    });

    it('should truncate to length and add an ellipsis', function () {

        expect(truncate(unfiltered, 3)).to.equal("one...");
    });

    it('should round to word boundaries', function () {

        expect(truncate(unfiltered, 10)).to.equal("one two...");
    });

    it('should split a word to avoid returning an empty string', function () {

        expect(truncate(unfiltered, 2)).to.equal("on...");
    });

    it('should tolerate non string inputs', function () {

        expect(truncate(434578932, 4)).to.equal("4345...");
    });

    it('should tolerate falsey inputs', function () {

        expect(truncate(0, 4)).to.equal("0");

        expect(truncate(false, 4)).to.equal("fals...");
    });
});
SharkAlley
  • 11,399
  • 5
  • 51
  • 42
3

You can limit the length of a string or an array by using a filter. Check this one written by the AngularJS team.

Thomas W
  • 14,757
  • 6
  • 48
  • 67
MAM
  • 31
  • 1
  • 3
3

In html its used along with limitTo filter provided by angular itself as below,

    <p> {{limitTo:30 | keepDots }} </p>

filter keepDots :

     App.filter('keepDots' , keepDots)

       function keepDots() {

        return function(input,scope) {
            if(!input) return;

             if(input.length > 20)
                return input+'...';
            else
                return input;

        }


    }
Shushanth Pallegar
  • 2,832
  • 1
  • 14
  • 16
3

If you want something like : InputString => StringPart1...StringPart2

HTML:

<html ng-app="myApp">
  <body>
    {{ "AngularJS string limit example" | strLimit: 10 : 20 }}
  </body>
</html>

Angular Code:

 var myApp = angular.module('myApp', []);

 myApp.filter('strLimit', ['$filter', function($filter) {
   return function(input, beginlimit, endlimit) {
      if (! input) return;
      if (input.length <= beginlimit + endlimit) {
          return input;
      }

      return $filter('limitTo')(input, beginlimit) + '...' + $filter('limitTo')(input, -endlimit) ;
   };
}]);

Example with following parameters :
beginLimit = 10
endLimit = 20

Before: - /home/house/room/etc/ava_B0363852D549079E3720DF6680E17036.jar
After: - /home/hous...3720DF6680E17036.jar

vhamon
  • 637
  • 4
  • 12
2
Use this in your html - {{value | limitTocustom:30 }}

and write this custom filter in your angular file,

app.filter('limitTocustom', function() {
    'use strict';
    return function(input, limit) {
        if (input) {
            if (limit > input.length) {
                return input.slice(0, limit);
            } else {
                return input.slice(0, limit) + '...';
            }
        }
    };
});

// if you initiate app name by variable app. eg: var app = angular.module('appname',[])
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118
2

This may not be from the script end but you can use the below css and add this class to the div. This will truncate the text and also show full text on mouseover. You can add a more text and add a angular click hadler to change the class of div on cli

.ellipseContent {
    overflow: hidden;
    white-space: nowrap;
    -ms-text-overflow: ellipsis;
    text-overflow: ellipsis;
}

    .ellipseContent:hover {
        overflow: visible;
        white-space: normal;
    }
Kurkula
  • 6,386
  • 27
  • 127
  • 202
2

If you have two bindings {{item.name}} and {{item.directory}}.

And want to show the data as a directory followed by the name, assuming '/root' as the directory and 'Machine' as the name (/root-machine).

{{[item.directory]+[isLast ? '': '/'] + [ item.name]  | limitTo:5}}
Floern
  • 33,559
  • 24
  • 104
  • 119
  • Is there any chance you posted this answer on the wrong question? This doesn't appear to have anything to do with limiting the length of a string with AngularJS. – BSMP Aug 17 '17 at 00:03
2
<div>{{modal.title | slice: 0: 20}}</div>
sdkcy
  • 3,528
  • 1
  • 16
  • 23
Vikas
  • 71
  • 10
1

You can use this npm module: https://github.com/sparkalow/angular-truncate

Inject the truncate filter into your app module like this:

var myApp = angular.module('myApp', ['truncate']); 

and apply the filter in your app this way:

{{ text | characters:20 }} 
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
Mel Michael
  • 141
  • 1
  • 4
1

I would use the following a ternary operator alternative to accomplish the truncation with ... as follow:

<div>{{ modal.title.length > 20 ? (modal.title | limitTo : 20) + '...' : modal.title }}</div>
hmg
  • 186
  • 1
  • 7
0

I created this directive that easily does that, truncates the string to a specified limit and adds a "show more/less" toggle. You can find it on GitHub: https://github.com/doukasd/AngularJS-Components

it can be used like this:

<p data-dd-collapse-text="100">{{veryLongText}}</p>

Here's the directive:

// a directive to auto-collapse long text
app.directive('ddCollapseText', ['$compile', function($compile) {
return {
    restrict: 'A',
    replace: true,
    link: function(scope, element, attrs) {

        // start collapsed
        scope.collapsed = false;

        // create the function to toggle the collapse
        scope.toggle = function() {
            scope.collapsed = !scope.collapsed;
        };

        // get the value of the dd-collapse-text attribute
        attrs.$observe('ddCollapseText', function(maxLength) {
            // get the contents of the element
            var text = element.text();

            if (text.length > maxLength) {
                // split the text in two parts, the first always showing
                var firstPart = String(text).substring(0, maxLength);
                var secondPart = String(text).substring(maxLength, text.length);

                // create some new html elements to hold the separate info
                var firstSpan = $compile('<span>' + firstPart + '</span>')(scope);
                var secondSpan = $compile('<span ng-if="collapsed">' + secondPart + '</span>')(scope);
                var moreIndicatorSpan = $compile('<span ng-if="!collapsed">...</span>')(scope);
                var toggleButton = $compile('<span class="collapse-text-toggle" ng-click="toggle()">{{collapsed ? "less" : "more"}}</span>')(scope);

                // remove the current contents of the element
                // and add the new ones we created
                element.empty();
                element.append(firstSpan);
                element.append(secondSpan);
                element.append(moreIndicatorSpan);
                element.append(toggleButton);
            }
        });
    }
};
}]);

And some CSS to go with it:

.collapse-text-toggle {
font-size: 0.9em;
color: #666666;
cursor: pointer;
}
.collapse-text-toggle:hover {
color: #222222;
}
.collapse-text-toggle:before {
content: '\00a0(';
}
.collapse-text-toggle:after {
content: ')';
}
Dimitris
  • 13,480
  • 17
  • 74
  • 94
0

This solution is purely using ng tag on HTML.

The solution is to limit the long text displayed with 'show more...' link at the end of it. If user click 'show more...' link, it will show the rest of the text and removed the 'show more...' link.

HTML:

<div ng-init="limitText=160">
   <p>{{ veryLongText | limitTo: limitText }} 
       <a href="javascript:void(0)" 
           ng-hide="veryLongText.length < limitText" 
           ng-click="limitText = veryLongText.length + 1" > show more..
       </a>
   </p>
</div>
Amirul
  • 542
  • 6
  • 15
0

THE EASIEST SOLUTION --> i've found is to let Material Design (1.0.0-rc4) do the work. The md-input-container will do the work for you. It concats the string and adds elipses plus it has the extra advantage of allowing you to click it to get the full text so it's the whole enchilada. You may need to set the width of the md-input-container.

HTML:

<md-input-container>
   <md-select id="concat-title" placeholder="{{mytext}}" ng-model="mytext" aria-label="label">
      <md-option ng-selected="mytext" >{{mytext}}
      </md-option>
   </md-select>
</md-input-container>

CS:

#concat-title .md-select-value .md-select-icon{
   display: none; //if you want to show chevron remove this
}
#concat-title .md-select-value{
   border-bottom: none; //if you want to show underline remove this
}
Post Impatica
  • 14,999
  • 9
  • 67
  • 78
0

Limit the number of words with a custom Angular filter: Here is how I used an Angular filter to limit the number of words displayed using a custom filter.

HTML:

<span>{{dataModelObject.TextValue | limitWordsTo: 38}} ......</span>

Angular/Javascript Code

angular.module('app')
.filter('limitWordsTo', function () {
    return function (stringData, numberOfWords) {
        //Get array of words (determined by spaces between words)
        var arrayOfWords = stringData.split(" ");

        //Get loop limit
        var loopLimit = numberOfWords > arrayOfWords.length ? arrayOfWords.length : numberOfWords;

        //Create variables to hold limited word string and array iterator
        var limitedString = '', i;
        //Create limited string bounded by limit passed in
        for (i = 0; i < loopLimit; i++) {
            if (i === 0) {
                limitedString = arrayOfWords[i];
            } else {
                limitedString = limitedString + ' ' + arrayOfWords[i];
            }
        }
        return limitedString;
    }; 
}); //End filter
Geoff
  • 1
0

It works ok for me 'In span', ng-show = "MyCtrl.value.$viewValue.length > your_limit" ...read more. 'end span'

G. K.
  • 29
  • 5
0

I use nice set of useful filter library "Angular-filter" and one of them called "truncate" is useful too.

https://github.com/a8m/angular-filter#truncate

usage is:

text | truncate: [length]: [suffix]: [preserve-boolean]
Lukas Jelinek
  • 2,337
  • 1
  • 19
  • 12
0

ng-keypress="filterValue($event)" ng-model="customer.CUSTOMER_PHONE"

$scope.filterValue = function($event){

        if(isNaN(String.fromCharCode($event.keyCode)) ){
            $event.preventDefault();
        }
        if($scope.customer.CUSTOMER_PHONE.length <= 11)
        {              
            $scope.customer.CUSTOMER_PHONE = $scope.customer.CUSTOMER_PHONE;
        }
        else
        {
            $event.preventDefault();
        }

    };
Rahee
  • 1
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 01 '22 at 07:32