Rene Jorgensen
Rene Jorgensen

Reputation: 179

Limit input to textarea without unnecessary constraints

I am looking for a method to limit input to a textarea in a way that enables user input to stay within a specified area WITHOUT unnecessary constraints to maximum number of characters.

The obvious method is maxlength, but that means maxlength will be determined by how much space an all caps input would take up, and that will require a maxlength that is unnecessarily low.

There are also various JS / jQuery solutions that limit the amount of lines possible to input in a text area (e.g. Limit number of lines in textarea and Display line count using jQuery), but these solutions, as far as I have been able to find, are dependent on the ENTER key, but doesn’t work if you copy-paste a piece of text into the text area.

To clarify

<!doctype html>
<head>
    <style>
    .one{
        height: 60px;
        width: 55px;
        background-color: pink;
        font-size: 16px;
    }
    </style>    
</head>
<body>
    <div class="one">i i i i i i i i i i i i i i i i i i</div>
    <br>
    <div class="one">M M M M M M M M M</div>
</body>
</html>

Div one can contain 18 lowercase “i” but only 9 capital “M”, so in order to ensure input would never exceed div one, the maxlength would have to be set to 9. The general result would be that the Div one area would generally not be fully used.

The above is merely a simple example to quickly explain which output I desire. The solution should ofc be tied to an input via a form textfield.

Ideas?

Cheers

Upvotes: 3

Views: 365

Answers (2)

Rene Jorgensen
Rene Jorgensen

Reputation: 179

Here's my bid on a solution to the problem. There are a few bugs, but I'm quite satisfied with it.

I spend a lot of time trying to work something out by counting lines in the text area, but abandoned the effort as I came across increasingly complex solutions.

This solution depends on the div height and trims a .substring generated from the textarea user input so it fits within the desired div, in this case myDiv. The trimed string is also put into a second textarea which will be the one used in the form.

<!doctype html>
<head>
    <script src="https://code.jquery.com/jquery-1.10.2.js"></script>

   <style>
    .myDiv{
        min-height: 100px;
        width: 100px;
        background-color: pink;
        position: absolute;
    }
    #mySecondDiv{
        background-color: transparent;
        border: 1px solid black;
    };
    </style>

</head>
<body>

<textarea id='userInput' cols="30" rows="7"></textarea>
<textarea id="toBeStored"></textarea>

<div class='myDiv'></div>
<div class='myDiv'></div>
<div class='myDiv' id='mySecondDiv'></div>

<script>
//For live versions set the 'left' property for .myDiv(0) and #toBeStored to negative so they are off screen
$('.myDiv').eq(0).offset({ top: 200, left: 350 });
$('#toBeStored').offset({ top: 10, left: 350});

$('.myDiv').eq(1).offset({ top: 200, left: 10 });
$('.myDiv').eq(2).offset({ top: 200, left: 10 });

var currentMaxChars = 0;
var testString = "";
var myDivHeight = $('.myDiv').height()

$(document).ready(function(){
    while($('.myDiv').eq(0).height() <= myDivHeight ){
        testString += " i";
        $('.myDiv').eq(0).html(testString);
        currentMaxChars++;
    };
    currentMaxChars = currentMaxChars*2;
    maxChars = currentMaxChars;

    $("#userInput").on('change keyup paste', function() {
        var input = $(this).val().replace(/\n/g, '<br/>');
        $('.myDiv').eq(1).html(input);

        var str = $('#userInput').val().replace(/\n/g, '<br/>');
        if(str.length == currentMaxChars){
            currentMaxChars = maxChars;
        };

        if($('.myDiv').eq(0).height() <= myDivHeight){
            $('.myDiv').eq(0).html(str.substring(0, currentMaxChars));
            $('#toBeStored').html(str.substring(0, currentMaxChars));
        } else {
            while($('.myDiv').eq(0).height() > myDivHeight){
                currentMaxChars--;
                $('.myDiv').eq(0).html(str.substring(0, currentMaxChars));
                $('#toBeStored').html(str.substring(0, currentMaxChars));
            };
        };
    });
});
</script>
</body>
</html>

Upvotes: 0

Someone
Someone

Reputation: 3568

I can't see this being an easy problem to solve. There is probably someone out there with more expertise than I, but the only way I can immediately think of to do this is to create a Map of characters and to assign them a width. Using this map, you could compare any new input against the map and determine how long/wide the input is.

Example pseudo code, this probably won't work as is;

   // YOUR CHAR MAP WITH WIDTHS ASSIGNED TO LETTERS
    var charMap = {
      i: 1,
      M: 2
    }

   // MAX AMOUNT OF CHARACTERS
   var charLimit = 18;

   // ASSUME THE TEXTAREA IS EMPTY, COULD GET ACTUAL WIDTH HERE INSTEAD
   var currentChars = 0;

   $('textarea').on('change', function{
     // GET ALL NEW INPUT
     var chars = $(this).val();
     // FOR LIMITING THE INPUT, THIS IS THE FINAL STRING THAT WILL END UP IN THE TEXTBOX
     var limitedUserInput = '';

     // CHECK EACH CHAR ONE BY ONE, COMPARING ITS WIDTH USING THE MAP
     for(var x = 0; x < chars.length; x++){
       currentChars += chars[x];
       // IF SIZE LIMIT NOT HIT, ADD CHARACTER TO OUTPUT STRING
       if(currentChars < charLimit){
         limitedUserInput += chars[x];
       }
     }

     // DISPLAY THE OUTPUT IN THE TEXT AREA (TRIMMING ANY EXTRA CONTENT)
     $(this).html = limitedUserInput;
   })

This would allow you to have 18 x charMap.i (18) or 9 x charMap.M (18).

I hope that makes some kind of sense.

Upvotes: 2

Related Questions