views:

188

answers:

4

I was given an unusual request recently that I'm having the most difficult time addressing that involves capturing all display-characters when typed into a text box. The set up is as follows:

I have a text box that has a maxlength of 10 characters. When the user attempts to type more than 10 characters, I need to notify the user that they're typing beyond the character count limit.

The simplest solution would be to specify a maxlength of 11, test the length on every keyup, and truncate back down to 10 characters but this solution seems a bit kludgy. What I'd prefer to do is capture the character before keyup and, depending on whether or not it is a display-character, present the notification to the user and prevent the default action.

A white-list would be challenging since we handle a lot of international data.

I've played around with every combination of keydown, keypress, and keyup, reading event.keyCode, event.charCode, and event.which, but I can't find a single combination that works across all browsers. The best I could manage is the following that works properly in >=IE6, Chrome5, FF3.6, but fails in Opera:

NOTE: The following code utilizes jQuery.

$(function(){
  $('#textbox').keypress(function(e){
    var $this = $(this);
    var key = ('undefined'==typeof e.which?e.keyCode:e.which);
    if ($this.val().length==($this.attr('maxlength')||10)) {
      switch(key){
        case 13: //return
        case 9:  //tab
        case 27: //escape
        case 8:  //backspace
        case 0:  //other non-alphanumeric
          break;
        default:
          alert('no - '+e.charCode+' - '+e.which+' - '+e.keyCode);
          return false;
      };
    }
  });
});

I'll grant that what I'm doing is likely over-engineering the solution but now that I'm invested in it, I'd like to know of a solution. Thanks for your help!

A: 

Since you're using JQuery already, .validate() is terrific for forms. Just set a rule of maxlength for your field, and you're good to go. E.g.

$("form[name='myform']").validate({
    rules: {
        myfield: {required:true, maxlength:10}
    }
});
dnagirl
Thanks for the tip but this doesn't address the problem at hand. 10 characters is the hard limit, I need to live test if the user attempts to type beyond the hard limit.
Jean-Charles
+1  A: 

The simplest solution would be to specify a maxlength of 11, test the length on every keyup, and truncate back down to 10 characters but this solution seems a bit kludgy.

It is also easily defeated by cut/paste, drag/drop, right-click-undo/redo, etc. There's no reliable way to get every potential bit of input short of polling.

Why not set maxlength to 10, to let the browser enforce the limit properly, and just show a warning if there is another attempted keypress? You don't need to prevent any default action because the browser is already taking care of the length, so the amount of key checking you have to do is lower.

<input id="x" maxlength="10"/>
<div id="x-warning" style="display: none;">can't type any more!</div>
<script type="text/javascript">
    function LengthMonitor(element, warning) {
        element.onkeypress= function(event) {
            if (event===undefined) event= window.event;
            var code= 'charCode' in event? event.charCode : 'which' in event? event.which : event.keyCode;
            var full= element.value.length===element.maxLength;
            var typed= !(code<32 || event.ctrlKey || event.altKey || event.metaKey);
            warning.style.display= (full & typed)? 'block' : 'none';
        };
        element.onblur= function() {
            warning.style.display= 'none';
        };
    }

    LengthMonitor(document.getElementById('x'), document.getElementById('x-warning'));
</script>
bobince
Works to some degree but charCode is an unsupported property in IE and Opera.
Jean-Charles
Yeah, you can try falling back to `which` and then `keyCode` for those browsers. Unfortunately `keypress` is wonky (for example in IE you can't tell the difference between page-up and `!`). If you want to do it reliably you'd have to trap `keydown` instead and keep a list of the keycodes that do or don't mean a real character. Not much fun.
bobince
A: 

I had a vaguely similar situation come up in a web-app I am working on where I needed to give feedback to the user, live, as they entered data into an input.

Honestly, the best solution I came up with was just to use a setTimeout to poll the input box periodically. I did a few tests to find a nice balance between responsiveness and efficiency (I think ~400ms).

It works great, and is much better than trying to kludge together event handlers for every scenario (key-down, on-change, etc etc).

It's not as elegant as I would like, but it works.

If you really want to do this, I would watch the input in real time, checking it's length. If it's over the limit, chop it and alert the user.

This would not be a replacement for other validation of course.

I would also consider that this may be unnecessary. I suppose it's nice, but most websites get by with a hard limit and validation-on-submission.

MisterMister
A: 

How about presenting a message to the user when they go over the limit, but not truncating their input? You can prevent submission using the onsubmit event and the user will never have the poor experience of a maxlength or a transient input. You can highlight the box in red or display an icon as well to really drive the point home.

However, this is all client-side, so if you really need to validate the input, that must be built into the submission target's server-side logic (in the case of a form).

Alternatively, if this is happening in real-time, link the logic to a variable that is set by the key-up event. If the length limit is exceeded, present an error message, do not truncate, and do not update the private variable.

Anthony DiSanti