Limit the length of a string with AngularJS
Asked Answered
P

27

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?

Photogenic answered 7/8, 2013 at 6:0 Comment(1)
jsfiddle.net/tUyyxNottinghamshire
S
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)

Sounder answered 7/8, 2013 at 6:24 Comment(10)
There's an equivalent at angular-modules: ngmodules.org/modules/angularjs-truncateGoodnatured
angularjs-truncate isn't solution, but your IS solution. Thank you! Make it as module!Noleta
@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!Weiler
this works fine when we use it like this {{post.post_content | cut:true:100:' ...'}} But fails when i use like this <span ng-bind-html="trustedHtml(post.post_content| cut:true:100:' ...')"></span> Because i am forced to use it with trusted html in my caseGiantess
The wordwise limit is a nice feature that doesnt seem to exist in the default "limitTo"Len
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.Nicholas
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; }Stet
@EpokK: Thanks. how about adding read more link if cut happensJud
@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.Infinite
@Infinite Hehehe, really old :) TkxWeiler
R
510

Here is the simple one line fix without css.

{{ myString | limitTo: 20 }}{{myString.length > 20 ? '...' : ''}}
Roundhead answered 17/9, 2014 at 13:49 Comment(11)
Simple and elegant. Instead of '...' you can also use the HTML entity for ellipsis: '&hellip;'Executor
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! :)Monarchy
awesome! is there a way to cut after a number of lines, rather than after a number of characters?Soil
@Soil You need to try that in css or write a directive to achieve that.Roundhead
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, @RoundheadCooler
Please what if I want to apply a limit to the total length of two strings?Pittsburgh
@Lig Please elaborate. Any example of what you require will be helpful.Roundhead
@Roundhead 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?Pittsburgh
@Lig have to write custom filter for this. If you wish ask a separate question and post the link here. I ll answer that.Roundhead
But this solution doesn't have support for word wise cutTillotson
How can i do this with ng-bind-html ?Pepin
S
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)

Sounder answered 7/8, 2013 at 6:24 Comment(10)
There's an equivalent at angular-modules: ngmodules.org/modules/angularjs-truncateGoodnatured
angularjs-truncate isn't solution, but your IS solution. Thank you! Make it as module!Noleta
@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!Weiler
this works fine when we use it like this {{post.post_content | cut:true:100:' ...'}} But fails when i use like this <span ng-bind-html="trustedHtml(post.post_content| cut:true:100:' ...')"></span> Because i am forced to use it with trusted html in my caseGiantess
The wordwise limit is a nice feature that doesnt seem to exist in the default "limitTo"Len
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.Nicholas
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; }Stet
@EpokK: Thanks. how about adding read more link if cut happensJud
@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.Infinite
@Infinite Hehehe, really old :) TkxWeiler
I
62

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
Individualism answered 9/5, 2014 at 14:42 Comment(4)
This solution is missing the "...". The result should be: "My String..."Registered
I'm not seeing the ellipsis here: plnkr.co/edit/HyAejS2DY781bqcT0RgV?p=preview. Can you elaborate?Individualism
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.Coffeepot
@Coffeepot thanks for pointing that out. I probably should have made a comment to EpokK's answer instead of another answer.Individualism
W
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;
   }
Worsen answered 7/8, 2013 at 6:42 Comment(7)
text-overflow: ellipsis, nice one.Throughout
this technique, while awesome, prevents text from wrappingLamoreaux
This is the correct answer. My general rule is: "don't do in JavaScript that which can be done in CSS".Sunlit
This only works for text with one line per paragraph. See for multiline css-tricks.com/line-clampin (not all browsers support that).Principality
This also works if you are trying to limit the length of an array ng-repeat.Isochronize
Its a perfect css-pure solution for single line - wont work if you need multiple lines because of the 'white-space: nowrap; 'Newsmonger
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 yLucio
F
27

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

{{ longString | limitTo: 20 }} {{longString.length < 20 ? '' : '...'}}
Folderol answered 19/12, 2014 at 20:51 Comment(1)
I would remove the whitespace between both outputs to avoid line breakNewsmonger
R
22
< div >{{modal.title | limitTo:20}}...< / div>
Religiose answered 15/7, 2016 at 18:51 Comment(1)
Simplest approach, yet functional. But it assumes that every title would have more than 20 characters and this, in some cases, may be unexpected.Polysepalous
S
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

Stickup answered 1/12, 2014 at 5:28 Comment(1)
Can I suggest adding a return in case the input value is dynamic? i.e. if (!input) {return;} Otherwise there will be JS console errorsMarrero
G
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>
Gaither answered 12/2, 2016 at 20:49 Comment(0)
O
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

Ogre answered 5/6, 2017 at 21:25 Comment(0)
F
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>
Freeness answered 29/8, 2016 at 9:49 Comment(0)
S
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...");
    });
});
Spradling answered 1/11, 2014 at 8:59 Comment(0)
B
3

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

Buffum answered 12/2, 2014 at 6:4 Comment(1)
provide some more details alsoRustic
H
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;

        }


    }
Hootenanny answered 1/2, 2015 at 11:53 Comment(0)
A
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

Arango answered 5/10, 2016 at 13:6 Comment(0)
F
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',[])
Faradism answered 8/12, 2015 at 12:55 Comment(0)
F
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;
    }
Fraenum answered 11/2, 2016 at 19:23 Comment(0)
W
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}}
Wroth answered 16/8, 2017 at 22:32 Comment(1)
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.Scalade
T
2
<div>{{modal.title | slice: 0: 20}}</div>
Tace answered 20/8, 2019 at 8:1 Comment(0)
G
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 }} 
Goosander answered 29/10, 2015 at 10:22 Comment(0)
B
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>
Brawny answered 16/11, 2020 at 13:56 Comment(0)
T
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: ')';
}
Tradeswoman answered 7/8, 2014 at 14:52 Comment(0)
A
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>
Averell answered 17/12, 2015 at 10:59 Comment(0)
D
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
}
Diphosgene answered 16/2, 2016 at 16:30 Comment(0)
A
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
Ancona answered 1/6, 2016 at 18:52 Comment(0)
R
0

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

Robbinrobbins answered 12/8, 2016 at 5:22 Comment(0)
A
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]
Abduction answered 29/9, 2017 at 9:28 Comment(0)
A
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();
        }

    };
Approachable answered 1/6, 2022 at 5:54 Comment(1)
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.Fy

© 2022 - 2024 — McMap. All rights reserved.