Limiting number of lines in textarea
Asked Answered
N

8

35

I'm looking for a javascript that can limit the number of lines (by line I mean some text ended by user pressing enter on the keyboard) the user is able to enter in textarea. I've found some solutions but they simply don't work or behave really weird. The best solution would be a jquery plugin that can do the work - something like CharLimit, but it should be able to limit text line count not character count.

Noncompliance answered 17/2, 2009 at 13:23 Comment(1)
Define "line". Visible lines? Lines delimited by a '\n' or something else?Kolnick
B
23

This might help (probably be best using jQuery, onDomReady and unobtrusively adding the keydown event to the textarea) but tested in IE7 and FF3:

<html>
  <head><title>Test</title></head>
  <body>
    <script type="text/javascript">
      var keynum, lines = 1;

      function limitLines(obj, e) {
        // IE
        if(window.event) {
          keynum = e.keyCode;
        // Netscape/Firefox/Opera
        } else if(e.which) {
          keynum = e.which;
        }

        if(keynum == 13) {
          if(lines == obj.rows) {
            return false;
          }else{
            lines++;
          }
        }
      }
      </script>
    <textarea rows="4" onkeydown="return limitLines(this, event)"></textarea>
  </body>
</html>

*Edit - explanation: It catches the keypress if the ENTER key is pressed and just doesn't add a new line if the lines in the textarea are the same number as the rows of the textarea. Else it increments the number of lines.

Edit #2: Considering people are still coming to this answer I thought I'd update it to handle paste, delete and cut, as best as I can.

<html>

<head>
    <title>Test</title>
    <style>
        .limit-me {
            height: 500px;
            width: 500px;
        }
    </style>
</head>

<body>
<textarea rows="4" class="limit-me"></textarea>

<script>
    var lines = 1;

    function getKeyNum(e) {
        var keynum;
        // IE
        if (window.event) {
            keynum = e.keyCode;
            // Netscape/Firefox/Opera
        } else if (e.which) {
            keynum = e.which;
        }

        return keynum;
    }

    var limitLines = function (e) {
        var keynum = getKeyNum(e);

        if (keynum === 13) {
            if (lines >= this.rows) {
                e.stopPropagation();
                e.preventDefault();
            } else {
                lines++;
            }
        }
    };

    var setNumberOfLines = function (e) {
        lines = getNumberOfLines(this.value);
    };

    var limitPaste = function (e) {
        var clipboardData, pastedData;

        // Stop data actually being pasted into div
        e.stopPropagation();
        e.preventDefault();

        // Get pasted data via clipboard API
        clipboardData = e.clipboardData || window.clipboardData;
        pastedData = clipboardData.getData('Text');

        var pastedLines = getNumberOfLines(pastedData);

        // Do whatever with pasteddata
        if (pastedLines <= this.rows) {
            lines = pastedLines;
            this.value = pastedData;
        }
        else if (pastedLines > this.rows) {
            // alert("Too many lines pasted ");
            this.value = pastedData
                .split(/\r\n|\r|\n/)
                .slice(0, this.rows)
                .join("\n ");
        }
    };

    function getNumberOfLines(str) {
        if (str) {
            return str.split(/\r\n|\r|\n/).length;
        }

        return 1;
    }

    var limitedElements = document.getElementsByClassName('limit-me');

    Array.from(limitedElements).forEach(function (element) {
        element.addEventListener('keydown', limitLines);
        element.addEventListener('keyup', setNumberOfLines);
        element.addEventListener('cut', setNumberOfLines);
        element.addEventListener('paste', limitPaste);
    });
</script>
</body>
</html>
Bumbledom answered 17/2, 2009 at 15:3 Comment(2)
This has a problem when the user hit the backspace leading to the deletion of the whole line which will then limit the number of rows available to write on, and possibly delete all the rows leaving only one line to write. It is also not doing well when the user enters a lot of characters that make them to move into a new line but then the line created was not counted to limit the line.Rother
I have created a helper with jquery and bootstrap to aply rules on textarea and it's also validate vhen user paste code in it. This is my first gitHub project. Free to use and modify. github.com/werddomain/TextAreaLimitationVizard
C
16

How to do it with jQuery:

Bind to keyDown event of textarea.

function limitTextareaLine(e) {
    if(e.keyCode == 13 && $(this).val().split("\n").length >= $(this).attr('rows')) { 
        return false;
    }
}
Channelize answered 27/6, 2011 at 6:13 Comment(2)
Hi Maciej, thanks for the answer. Can you provide an example of this please?Sphagnum
This strategy fails when user pastes newlines into the textarea.Reinertson
M
7

This solution works:

<script type="text/javascript">
    function limitTextarea(textarea, maxLines, maxChar) {
        var lines = textarea.value.replace(/\r/g, '').split('\n'), lines_removed, char_removed, i;
        if (maxLines && lines.length > maxLines) {
            lines = lines.slice(0, maxLines);
            lines_removed = 1
        }
        if (maxChar) {
            i = lines.length;
            while (i-- > 0) if (lines[i].length > maxChar) {
                lines[i] = lines[i].slice(0, maxChar);
                char_removed = 1
            }
            if (char_removed || lines_removed) {
                textarea.value = lines.join('\n')
            }
        }
    }
</script>

and text area would be

<asp:TextBox ID="myWishTB" runat="server" Height="185px" TextMode="MultiLine" 
             Style="overflow: auto;" Width="95%" 
             onkeyup="limitTextarea(this,10,80)">
</asp:TextBox>

in regular HTML:

<textarea id="textareaID" onkeyup="limitTextarea(this,5,100)" cols="20" rows="5">   </textarea>
Maribelmaribelle answered 18/12, 2012 at 22:24 Comment(0)
A
7

jQuery example. This works for both typing and pasting.

  //Limit to # of rows in textarea or arbitrary # of rows
  $('#yourtextarea').bind('change keyup', function(event) {
    //Option 1: Limit to # of rows in textarea
    rows = $(this).attr('rows');
    //Optiion 2: Limit to arbitrary # of rows
    rows = 6;

    var value = '';
    var splitval = $(this).val().split("\n");

    for(var a=0;a<rows && typeof splitval[a] != 'undefined';a++) {
      if(a>0) value += "\n";
      value += splitval[a];
    }
    $(this).val(value);
  });
Avar answered 6/9, 2013 at 20:52 Comment(0)
D
4

(Done with jquery). It's not perfect but cares about wrapping. Not deppending only of the end of line (\n).
jquery scroll event have problems in mozilla and firefox if css overflow property in textarea is not auto, otherwise remove the corresponding lines and set overflow hidden. Could help the css resize:none and fixed height.

$('#textarea').scroll(function () {
    $(this).css("overflow", "hidden");      /* for the mozilla browser problem */
    $(this).animate({scrollTop: $(this).outerHeight()});
    while ($(this).scrollTop() > 0) {       /* for the copy and paste case */               
        lines=$(this).val().slice(0,-1);
        $(this).val(lines);
    }
    $(this).css("overflow", "auto");        /* For the mozilla browser problem */
});
Desimone answered 9/8, 2011 at 15:42 Comment(0)
K
3

The number of visible/display lines for a given block of text would vary with different browsers, fonts used, etc. You'd have to set a specific font and font-size, at a minimum, to be able to semi-reliably count display lines.

UPDATE: I see the edit. Then something like kevchadders code should do fine for you. You'll need js that counts chars and '\r\n's and checks against a user-defined limit. Also, if you don't use his script, make sure you use one that involves either a time interval check and/or the onKeyDown/onKeyUp events of the textarea. This may be why some scripts you have tested seem to "behave strangely".

Kolnick answered 17/2, 2009 at 13:31 Comment(0)
B
1

This is basically the same as Ivan's answer, using jQuery. I tested it for a project of my own; seems to work fine.

<script type="text/javascript" charset="utf-8">
  $(function() 
  {
    function getLines(id)
    {
      return $('#' + id).val().split("\n").length
    }

  $('#testing').keyup(function() 
  {
    var allowedNumberOfLines = 4;

    if(getLines('testing') > allowedNumberOfLines)
    {
      modifiedText = $(this).val().split("\n").slice(0, allowedNumberOfLines);
      $(this).val(modifiedText.join("\n"));
    }
  });
});
</script>
Bolinger answered 31/3, 2009 at 19:58 Comment(2)
getLines(id) should be getLines(el) where $('#testing') is sent directly to the getLines function. An easy optimization.Jotunheim
But does this work with automatically wrapped words as you type? Your function relies on newlines only.Diffidence
L
1

I extended it a bit to detect even overflow without a manual linebreak. This is for fixed size textarea with "overflow: hidden".

At the moment my solution makes the font smaller if it doesn't fit to textarea. And makes it larger again if possible.

var keynum, allowedLines = 5, defaultFontSize = 13/*px*/;

$(document).ready(function() {
    $("textarea").keydown(function(e, obj) {
        if(window.event)
            keynum = e.keyCode;
        else if (e.which)
            keynum = e.which;

        if (keynum == 13 && allowedLines <= $(this).val().split("\n").length)
            return false;
    });
    $("textarea").keyup(function(e, obj) {
        // Avoid copy-paste
        if (allowedLines < $(this).val().split("\n").length) {              
            lines = $(this).val().split("\n").slice(0, allowedLines);
            $(this).val( lines.join('\n') );
        }

        // Check overflow
        if ((this.clientHeight < this.scrollHeight)) {
            while ((this.clientHeight < this.scrollHeight)) {
                currFontSize = $(this).css('font-size');
                finalNum = parseFloat(currFontSize, 11);
                stringEnding = currFontSize.slice(-2);
                $(this).css('font-size', (finalNum-1) + stringEnding);
            }
        } else if ($(this).css('fontSize') != defaultFontSize+'px')  {
            while ($(this).css('font-size') != defaultFontSize+'px') {
                // First lets increase the font size
                currFontSize = $(this).css('font-size');
                finalNum = parseFloat(currFontSize, 11);
                stringEnding = currFontSize.slice(-2);
                $(this).css('font-size', (finalNum+1) + stringEnding);
                // lets loop until its enough or it gets overflow again
                if(this.clientHeight < this.scrollHeight) {
                    // there was an overflow and we have to recover the value
                    $(this).css('font-size', currFontSize);
                    break;
                }
            }
        }
    });
});
Lassa answered 3/12, 2011 at 23:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.