11

So many times we want to limit how much a user can write, but here I have a special sized box that it has to fit in, so I want to disable adding more characters if it would surpass a specific height. here is what I did:

var over;
$('textarea').keypress(function(e){
    var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
    var t = $(this).val();
    jQuery('<div/>', {
        style: "visibility:hidden",
        text: t,
        id: "test"
    }).appendTo('body');
    var h = $('#test').height();
    if(h >= 100){
        over = true;
    }
    else{
        over = false;
    }
    if(over){
        //code goes here
    }
    $('#test').remove();
});

I got the limiting code (what goes where I have the "code goes here" comment) from here and it ALMOST works.

There is only one problem:

if somebody copies and pastes, it can place multiple characters and therefore still go over the limit.

How can I fix this issue?

jsfiddle

Community
  • 1
  • 1
Ryan Saxe
  • 17,123
  • 23
  • 80
  • 128
  • What would you want to happen when someone copies and pastes over the limit... Show a message saying it's too big? Chop the string off at the character limit and paste that? Disable pasting altogether? – Dan-Nolan Aug 28 '13 at 15:06
  • I considered disabling pasting, but I'd rather not get rid of that dynamic quality. I guess what I would like to do is both of the examples you gave. let them know that it has run out of room, and cut off at the correct point – Ryan Saxe Aug 28 '13 at 15:27
  • I do not see the relationship between this question and that question... – Ryan Saxe Aug 28 '13 at 15:28
  • 2
    A few points: (1) if the font of the text area is different to that of the "special sized box" that the text needs to fit into, then you will have problems working out whether it fits, no matter what. Especially if the output box uses a non-proportional font. And (2) don't forget that no matter what you do in JS, it could potentially be overridden by a user with dev tools and a bit of JS knowledge. You therefore need to be able to do the same validation on the server as you are doing on the client. – Spudley Aug 28 '13 at 15:30
  • Take a look at http://stackoverflow.com/questions/3640187/how-can-i-modify-pasted-text. You could grab the incomming text and modify it in a way that it doesn't break your page. – Ben L. Aug 28 '13 at 15:31
  • @Spudley: the font is the same, I have already worked out those kinks. and it could be overwritten in dev tools, but that would not change how it shows up on their profile and such. – Ryan Saxe Aug 28 '13 at 15:42
  • @BenL.: I was thinking about doing that, but depending on the size of the paste, the iteration could be overwhelming especially if the user tries to type after. But I could try intercepting it and modifying it before it's posted – Ryan Saxe Aug 28 '13 at 15:43
  • Every font on every browser on every OS has the potential to render differently; most do. Even if you find code that works for you, it won't work for every one of your users. I have been in this situation dozens of times and the answer is always the same. Don't try to "fix" the fundamentals of computing and the web. I strongly recommend revisiting why this text area is so rigid in the first place. Are you absolutely certain it can't expand vertically to accommodate its content? If not, can't the user be responsible for making sure their content fits within the provided container? – Brent M Clark Sep 15 '13 at 02:21
  • this textarea is just like the textarea that I am typing in to make the omment. I have a version almost working, and it's fine regardless of the browser because it tests it in an invisible div. Plus the font is not customizable so that doesn't matter since I'll use something all broswers should process the same – Ryan Saxe Sep 15 '13 at 06:04

4 Answers4

1

Another somewhat hacky solution could be to check scroll on key up. If scroll exists, delete the last character while scroll exists:

function restrictScroll(e){
    if(e.target.clientHeight<e.target.scrollHeight){
        while(e.target.clientHeight<e.target.scrollHeight){
            e.target.value = e.target.value.substring(0, e.target.value.length-1);
        }
    }
};
document.getElementById("textareaid").addEventListener('keyup', restrictScroll);

This would work as you type and if you paste blocks of text. Large text blocks may take a little longer to loop through though. In which case you may want to split on "\n" and remove lines first, then characters.

jsfiddle

Eclectic
  • 847
  • 1
  • 11
  • 26
  • although this is a good idea, the text added on at the end does not get deleted. This is similar to how you can only have a set number of characters in a tweet, so if I did it this way people can still go over, it just wont display it in the actual textarea – Ryan Saxe Sep 11 '13 at 15:59
1

If you want your function to fire whenever the text in your field changes, you can bind it to the input and propertychange events, as per this answer:

Like this:

$('#descrip').on('input propertychange', function(e){

This will make sure your code fires when e.g. the user pastes in content using the mouse.

As for stopping them from entering content that would go over the limit, I think you have to keep track of what content they've entered yourself, and then revert their last edit if it infringed your criteria.

Note that e.g. Twitter doesn't stop the user from entering more characters if they've gone over the limit - they just tell the user they're over the limit, and tell them when they're back under. That might be the most usable design.

Community
  • 1
  • 1
Paul D. Waite
  • 96,640
  • 56
  • 199
  • 270
  • @RyanSaxe: it is a life-saver for this kind of thing. I believe you have to track the content of the changes yourself, and I don't think you can reject a change before it happens, but it's much easier than trying to detect keypresses and mouse clicks and so on. – Paul D. Waite Sep 18 '13 at 10:15
  • yeah, this will compress my code, but does not provide new functionality. My issue is how sloppy it looks when it goes over and then deletes itself. – Ryan Saxe Sep 18 '13 at 15:25
  • @RyanSaxe: "this will compress my code, but does not provide new functionality" - well, try pasting in content using the mouse with your old code, I bet that doesn't pick up the content change at all. I do see your point though. – Paul D. Waite Sep 18 '13 at 16:10
  • I have different code now that does pick it up. I have not updated the fiddle. – Ryan Saxe Sep 18 '13 at 16:33
0

You may try this:

$('#descrip').bind('paste',function(e) { 
    var el = $(this);
    setTimeout(function() {
        //Get text after pasting
        var text = $(el).val();
        //wath yu want to do
    }, 100);
};

Jsfiddle

The solution is taken from here and here. It works by binding to the paste event. Since paste event is fired before the text is pasted, you need to use a setTimeout to catch the text after pasting. There is still some rough edges (i.e. if you select text and press backspace, it does not update).

Still, Spudley comment has some valid points, that you may want to consider.

Edit:

Note on the jsfiddle: It allow you to go over the limit when pasting, but once over the limits, you cannot paste (or type) more text until you go under the limit again.

Must be taken into account that, since you are limiting the text length by the size it ocuppies after rendering (wich have it own issues as pointed by Spudley), and not a defined lenth, you can know if a text fits or not, but not know how much of the text is inside the limits, and how much is out of them.

You may consider reseting textbox value to its previous value if pasted text makes imput go over the limit, like in this one.

However, for cutting down the text after pasting so as non-fitting text is left out, but the rest of the pasted text is allowed, you need an entirely different approach. You may try iterating over the text until you find how much of the new text is enough.

By the way, line feeds and seems to cause your original script to behave weirdly.

Community
  • 1
  • 1
MACN
  • 196
  • 7
  • 13
0

I've been able to get the program working:

var over = false;
var num = 0;
var valid_entry = "";
$('#descrip').keyup(function(e){
    var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
    var t = $(this).val();
    getMaxRow(t,key,this);
});

function getMaxRow(t,key,obj) {
    jQuery('<div/>', {
            "class": "hide",
            text: t,
            id: "test"
        }).appendTo('body');
        var h = $('#test').height();
        $('#test').remove();
        if(h >= 100){
            num += 1;
            if(num == 1){
                var div = '<div id="message">You have run out of room</div>'
                $('body').append(div);
            }
            over = true;
        }
        else{
            over = false;
            valid_entry = t;
            if(num >= 1){
                $('#message').remove();
                num = 0;
            }
        }

        if( over ) {
            //Do this for copy and paste event:
            while ( over ) {
                 //Try using a substring here
                 t = t.substr(0,(t.length-1));
                 over = getMaxRow(t,key,obj);
            }
        }

        $(obj).val(valid_entry);

        return over;
}
Popsyjunior
  • 185
  • 10
  • So, I changed the event handler to the keyup, then I Introduced the valid_entry variable and assigned it to the current value of the textarea only when over was true.. Then I set the value of the textarea to the value of the valid entry at any time a key is released – Popsyjunior Sep 16 '13 at 13:54