0

It's well-documented that different browsers treat newlines in text areas differently with regards to maxlength. For example, the snippet below will behave differently in Chrome versus Firefox if you use newlines.

My problem is that I need to allow users to enter newlines and I need to show them how many characters they have left. I could detect their browser type, but that's brittle and is a known antipattern. Is there a way to use feature detection to do this properly? Or should I still just avoid maxlength? Note that my question is not jQuery-specific, I just used jQuery in my examples for the sake of simplicity in showing what was happening. Note that I have an example already of a workaround without maxlength (see below), but it doesn't translate well across frameworks like ember where you want to avoid using jquery hacks.

Maxlength issue (try with Firefox, Chrome, and type at least one newline

$('.t').on('input',function(){
  $('.x').html($('.t').val().length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="t" rows=3 maxlength=10></textarea>
<br>
chars typed: <span class="x"></span>

Without maxlength workaround (gross)

$('.t').on('input', function(){
  let maxLength = 10;
  let val = $('.t').val();
  $('.t').val((val && val.length) ? val.substring(0,maxLength) : val);
  $('.x').html($('.t').val().length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea class="t" rows=3></textarea>
Chars typed: <span class='x'></span>
Community
  • 1
  • 1
AlexMA
  • 9,842
  • 7
  • 42
  • 64

2 Answers2

0

You can use keydown and keyup events and regular expression which will replace all new lines characters with empty string. Than in the keydown event suppress type-in new character when the maxLength is reached, and in the keyup event display the number of characters left:

var maxLength = 10;
var navKeys = [8,46,27,38,40,33,34,13,37,39];
$(".x").html(maxLength);
$("textarea")
  .on("keydown", function(e){
    // Get value without new lines
    var val = $(this).val().replace(/\n|\r/g, "");

    // Allow nav keys
    if(navKeys.indexOf(e.keyCode) !== -1) {
      return true;
    }

    // Do not allow type in another char
    if(val.length >= maxLength) {
      e.preventDefault();
      return;
    }
  })
  .on("keyup", function(e) {
    // Get value without new lines
    var val = $(this).val().replace(/\n|\r/g, "");
    $(".x").html(maxLength - val.length);

    // Check the max length
    if(val.length > maxLength) {
      $(this).val(val.substr(0,maxLength));
    }
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
<br/>
chars typed: <span class="x"></span>

This worked for me in FF and also in Chrome.

xxxmatko
  • 4,017
  • 2
  • 17
  • 24
  • When you get to 10 characters, you can't use backspace anymore – AlexMA Aug 24 '16 at 14:43
  • Also doesn't prevent pasting in a million characters. – AlexMA Aug 24 '16 at 14:44
  • I made it as simple as possible, without handling navigation keys like `backspace`, `delete` etc. If you want I can add it to the sample. Also pasting is not problem, just handle another event with the same handler which checks the maxLength. Should I add it to the sample too? – xxxmatko Aug 24 '16 at 14:47
  • I've updated the sample to allow navigation keys. Hope it will help. – xxxmatko Aug 24 '16 at 15:18
0

I think the best choice is that you implement your own maxLength. Something like this:

var element = document.getElementById('textarea'),
  maxLength = 10;

var trim = function() {
  if(element.value.length >= maxLength) {
    element.value = element.value.substring(0, maxLength);
  }
};

// for older IE
element.onkeydown = function() {
  setTimeout(trim, 1);
};
// browser support: CH, IE 9+, FF 4.0, SF 5.0, OP
element.oninput = trim;
<textarea rows="3" id="textarea"></textarea>
jcbp
  • 475
  • 2
  • 10