1

How do I prevent the user from changing a string in an input box if the combined value of that input with their latest keypress does not pass a regular expression?

I see all kinds of examples on how to use keypress for testing individual characters, but I need to match the entire value to a regular expression, not just the key they pressed.

For example, The textbox needs to conform to the following regular expression:

"^023-[0-9]{0,7}$"

So if they want to change "023" to "23", it should stop them when they delete the 0 character. The same is true for deleting the - after 023. It should also stop them once they enter more than 7 numbers after 023. This cannot be done on blur. It must be done after every key stroke. Performance is not an issue.

If I use keypress() event in jQuery, and get the value of the input element like this:

$(this).val()

Then I will only get the value before they pressed the key - not after. Thus, there is no way to test the input against my regular expression. I cannot simply append the key pressed to this string, because I cannot make the assumption that they are only entering keys at the right-most side of the string.

I have looked into keydown/keyup events, and while keyup seems to give me the current value of the input after the user has pressed a key, I am finding it difficult to remove the effects of what they typed... which keypress() does not have a problem with apparently.

var regex = new RegExp("^023-[0-9]{0,7}$");

$("#number").keyup(function(event) {
    var number = $(this).val();

    if(!regex.test(number)) {
        event.preventDefault();

        return false;
    }
});

The above code just doesn't work. It seems keypress() gives me the ability to stop what they typed, but keyup gives me the ability to get the current value. I need a solution that does both ;)

The problem really stems from the fact that the browser has no MVC architecture. The model is the view. Unfortunately, we can't validate the updated model before the view is updated... because we need the view updated during a keyup event to get the updated model data... and by then, it's too late to prevent them from updating the view since it's already been updated.

6
  • you should consider validating on blur instead. running against a regex every keystroke is not the best idea for performance. Commented Jul 2, 2012 at 16:33
  • @jbabey: I always have to keep the 023- there in the field though. The requirements specify that the user never can change this. Commented Jul 2, 2012 at 16:39
  • then the 023- should be in a label (or readonly input) beside the box, not in the same box. Commented Jul 2, 2012 at 16:40
  • @jbabey: Requirements say it must be in the same box. Commented Jul 2, 2012 at 16:50
  • then i would push back on the requirements ;) Commented Jul 2, 2012 at 16:50

5 Answers 5

2

How about this:

var prevValue = "";
$("#number").keydown(function(e) {
   prevValue = $(this).val();
});

$("#number").keyup(function(e) {
...
   if(!regex.test(number))
      $(this).val(prevValue);
      // show error or other processing you need to do
});
Sign up to request clarification or add additional context in comments.

1 Comment

I've tried this as well about an hour ago. If you hold down characters rather than just press them, you will see that it does not work as expected. The problem is that this doesn't stop them from actually editing the text in the first place - it just replaces it after the fact, which is already too late. It is not a very robust solution.
1

try this:

var pattern = new RegExp("^023-[0-9]{0,7}$");

$("#number").change(function(e){
if (!pattern.test($(this).val())) {
      return false
    }
})

2 Comments

i agree with this solution. validation should happen on blur (or change), not every key stroke.
@undefined: the requirements dictate that "023-" cannot be changed by the user. If I resort to blur type of events, then the user can change it. The requirements also dictate that it must all be in a text box.
0

The event parameter that you have will contain all the details of the event that you are handling. This will include the key that was pressed.

Of note is that keydown and keyup events will return the key pressed, while keypress will return which character is entered which may be better for your choice.

See the help page here: http://api.jquery.com/keypress/ for more details.

In summary though event.which should do what you want. You can combine that with the original value of the textbox and from that get the new value. If it isn't valid then cancel the event, if it is valid then let it go...

4 Comments

I am not interested in just the key they pressed. I am much more interested in the total value of the input. The key "2" can be valid sometimes, and not others. It depends on the value of the element after they pressed the key.
But surely you can just do $(this).val()+event.which... if you know how to get the current value (whcih you have in the question) and the key pressed (which I just told you) then I'm not sure where your problem lies...
Why are you assuming that the entered text is always at the end of the string?
@egervari: Just a careless assumption I think. ;-) I just hadn't thought about putting characters in other places... I appreciate the answer is now no longer useful but may leave it there just in case anybody comes along and is happy with the last character only constraint you've pointed out.
0

If you can use the jQuery Validate plug-in, you can create a custom validator to match your RegEx. Then all you have to do is map the validator to that input. You'll still have to validate on the server-side, but you're probably already doing that.

1 Comment

I've done validation using this method in the past, even without plugin (plugin makes it easier). Unfortunately, this does not meet the requirements.
0

To do what you want, the jquery caret plugin is required. Please note that you'll need to remove the comments from the beginning of the file (or at least move them) or the byte order mark at the start of the code will cause an error.

So, what you need to do is capture the keypress, insert the character at the correct place in the string, check if that new string is valid and then either show the new insertion or not. I think the following does what you need:

$(document).ready(function(){
    var regex = new RegExp("^023-[0-9]{0,7}$");
    var caretpos;

    $('#number').keypress(function(event){
        // get the caret position
        caretpos = $(this).caret().start;
        //split the current value according to where the caret is
        valuestart = $(this).val().substring(0,caretpos);
        valueend = $(this).val().substring(caretpos);
        // insert the fired character into the string
        valuetocheck = valuestart + String.fromCharCode(event.which) + valueend;
        // check if the proposed new value passes the regex
        if (!regex.test(valuetocheck)) {
            // failed, prevent the character being shown
            event.preventDefault();
        }
    });
});

I've tested this in the latest versions of FF, Chrome, Safari, Opera and IE9. In FF and Opera, cursor key presses are completely ignored while they move the caret as usual in the other browsers so you may want to add some code to ensure consistent behaviour for that. You may also want to add some code to handle what will happen if the user selects some characters rather than just clicking into the input. The jquery caret plugin has usage examples for selections.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.