views:

351

answers:

6

I'm using the following Javascript to restrict a text field on my website to only accept numerical input, and no other letters or characters. The problem is, it REALLY rejects all other key inputs, like ctrl-A to select the text, or even any other browser functions like ctrl-T or ctrl-W while the text box is selected. Does anyone know of a better script to only allow numerical input, but not block normal commands (that aren't being directly input into the field)? Thanks Here is the code I'm using now:

function numbersonly(e, decimal) 
{
    var key;
    var keychar;

    if (window.event) 
        key = window.event.keyCode;
    else if (e) 
        key = e.which;
    else 
        return true;

    keychar = String.fromCharCode(key);

    if ((key==null) || (key==0) || (key==8) ||  (key==9) || (key==13) || (key==27))
       return true;     
    else if ((("0123456789").indexOf(keychar) > -1))
       return true;
    else if (decimal && (keychar == "."))
       return true;        
    else
       return false;
}

Edit: None of the solutions provided have solved my problem of allowing commands like ctrl-A while the text box is selected. That was the whole point of my asking here, so I have gone back to using my original script. Oh well.

+8  A: 

This is something I made another time for just numbers, it will allow all the formatters as well.

jQuery

$('input').keypress(function(e) {
    var a = [];
    var k = e.which;

    for (i = 48; i < 58; i++)
        a.push(i);

    if (!(a.indexOf(k)>=0))
        e.preventDefault();
});​

Try it

http://jsfiddle.net/zpg8k/

As a note, you'll want to filter on submit/server side as well, for sake of pasting/context menu and browsers that don't support the paste event.

Edit to elaborate on multiple methods

I see you're bouncing around the 'accepted' answer, so I'll clear something up. You can really use any of the methods listed here, they all work. What I'd personally do is use mine for live client side filtering, and then on submit and server side use RegEx as suggested by others. However, no client side by itself will be 100% effective as there is nothing stopping me from putting document.getElementById('theInput').value = 'Hey, letters.'; in the console and bypassing any clientside verification (except for polling, but I could just cancel the setInterval from the console as well). Use whichever client side solution you like, but be sure you implement something on submit and server side as well.

Edit 2 - @Tim Down

Alright, per the comments I had to adjust two things I didn't think of. First, keypress instead of keydown, which has been updated, but the lack of indexOf in IE (seriously Microsoft!?) breaks the example above as well. Here's an alternative

$('input').keypress(function(e) {
    var a = [];
    var k = e.which;

    for (i = 48; i < 58; i++)
        a.push(i);

    if (!($.inArray(k,a)>=0))
        e.preventDefault();
});​

New jsfiddle: http://jsfiddle.net/umNuB/

Robert
Hmm, I'm not sure this will work for me. It still seems to allow letters if you hold down the key. I want to prevent letters entirely, so that a form validation error is the last resort
RobHardgood
It's not allowing letters for me. As I said this was something I built before that had letters as well, but I removed that portion, make sure you're looking at the right jsfiddle.
Robert
It allows because someone messes around with his jsfiddle. Paste his javascript and you get what you want.
sod
Ohh, I see. You're right, I didn't notice the code was different. Can you explain what all those numbers are for var a? Are they the key codes for the numerical keys?
RobHardgood
The numbers are the formatters, backspace, shift etc etc etc. As you press a key it should show the keycode to the right, so you can play around and see what you want to allow and disallow.
Robert
Great! I think this will work perfectly :) thanks for explaining it too.
RobHardgood
Still allows me to right-click+paste text though.
dogbane
@fahd: As noted in the "make sure you verify server and on submit".
Robert
Sorry for the checkmark switching, I didn't realize you could only mark one (i'm a new member) but I'm using this solution. Thanks again Robert
RobHardgood
Don't use `keydown` or `keyup` for checking the character the user has typed. Any success you get will be coincidental and unreliable: a differently laid out keyboard or a keyboard from a culture other than your own will have different key mappings and your key codes will be useless. The only event that contains character information is `keypress`.
Tim Down
@Tim Down: A very valid point, I didn't think of that. Updated answer, hopefully Rob sees the notification.
Robert
One other issue: in IE up to and including version 8, arrays don't have an `indexOf` method.
Tim Down
Hmm @Tim Down, full of helpful tidbits that make me hate IE more, adjusted again.
Robert
Interesting, but now the browser commands no longer work again...
RobHardgood
What browser commands? I can still backspace etc etc. Which command specifically?
Robert
I'm talking about ctrl-A to highlight all the text in the field, and ctrl-T to open a new tab, etc. Usually they work find inside text fields. Using firefox
RobHardgood
Hmm they still work in Chrome, but not FireFox. It appears to be the way that FireFox handles the events, with Chrome intercepting the event before it's passed to the form, but Firefox not. I'll have to think a bit of a way to get around that...
Robert
Interesting... I just tried it in Opera and Safari too, and it works in Opera but not Safari.
RobHardgood
Also, what do you think would be the best way to call this function from my <input type="text"> tag? Or should it load when the page loads? I'm still kind of new to JS...
RobHardgood
I don't think there's a way around the FireFox problem because FireFox fires the event to the input as if it was just the key being pressed, not ctrl+key. As far as implementation, this uses a jQuery selector, so you'd use a selector equivalent to your input element. Non-jQuery would be something like `document.getElementById('elementId').onkeypress = function() {` then the rest stays the same except `e.preventDefault();` would change to `return false;`
Robert
Ah, I see. Thanks. Let me know if you think of a solution for this firefox thing...
RobHardgood
RobHardgood, have you tried my answer?
Tim Down
@Tim Down I'm trying it now
RobHardgood
+2  A: 

Just use regex to get rid of any non number characters whenever a key is pressed or the textbox loses focus.

var numInput;
window.onload = function () {   
    numInput = document.getElementById('numonly');
    numInput.onkeydown = numInput.onblur = numInput.onkeyup = function()
    {
        numInput.value = numInput.value.replace(/[^0-9]+/,"");
    }
}
Andrew Dunn
+1  A: 

http://jsfiddle.net/PgHFp/

<html>
<head>
<title>Test</title>
<script language="javascript">
function checkInput(ob) {
  var invalidChars = /[^0-9]/gi
  if(invalidChars.test(ob.value)) {
            ob.value = ob.value.replace(invalidChars,"");
      }
}
</script>
</head>

<body>
    <input type="text" onkeyup="checkInput(this)"/>
</body>
</html>
dogbane
This works great too! Thanks @fahd it even prevents pasting text
RobHardgood
Keep in mind it won't prevent dragging text into the textbox, hence the need for onsubmit and server side verification.
Robert
@Robert Indeed, I always have PHP form validation in case users have javascript turned off anyway.
RobHardgood
For some reason, this isn't working when I use onkeyup... It works great when I use onkeypress, but that makes it check a character too late...
RobHardgood
A: 

The only event that contains information about the character typed is keypress. Anything character-related you may infer from the keyCode property of keydown or keyup events is unreliable and dependent on a particular keyboard mapping. The following will prevent non-numeric keyboard input all major browsers by using the character obtained from the keypress event. It won't prevent the user from pasting or dragging non-numeric text in.

var input = document.getElementById("your_input");

input.onkeypress = function(evt) {
    evt = evt || window.event;
    if (!evt.ctrlKey && !evt.metaKey && !evt.altKey) {
        var charCode = (typeof evt.which == "undefined") ? evt.keyCode : evt.which;
        if (charCode && !/\d/.test(String.fromCharCode(charCode))) {
            return false;
        }
    }
};
Tim Down
@Tim Down this works well too, but again, it won't allow me to use functions like ctrl-A within the text box
RobHardgood
@RobHargood, my comment explained why that's so, because Firefox passes ctrl-t etc etc as if you're pressing just t, there's no reliable way to completely block the t letter in Firefox while allowing control-t. You can be reactive instead of proactive if you want that functionality, using `replace` like some of the other examples here.
Robert
Good point. I've updated my answer to check for the Ctrl key being pressed.
Tim Down
Robert, you can entirely reliably distinguish between `t` and `Ctrl-t` using the `ctrlKey` property of the event.
Tim Down
@TimDown, it's not working for me even when checking for control, Firefox on Mac for me is firing into the textfield as if it was only t being pressed.
Robert
Really? It works fine for me on my Mac. What are you pressing and what's going wrong?
Tim Down
Command+T which I assume `evt.metaKey` is supposed to allow?
Robert
Yes. Cmd-T works fine for me within the input in Firefox 3.6.
Tim Down
Hmm, I made another jsfiddle again to test it and it's working now, maybe I copied something wrong... oh well.
Robert
A: 

It's worth pointing out that no matter how tightly you manage to control this via the front end (Javascript, HTML, etc), you still need to validate it at the server, because there's nothing to stop a user from turning off javascript, or even deliberately posting junk to your form to try to hack you.

My advice: Use the HTML5 markup so that browsers which support it will use it. Also use the JQuery option previously suggested (the inital solution may have flaws, but it seems like the comments have been working through that). And then do server-side validation as well.

Spudley
+1  A: 

The following code is something I use extensively. I found the script in a forum, but modified and expanded it to accommodate my needs:

<script type="text/javascript">
    // Restrict user input in a text field
    // create as many regular expressions here as you need:
    var digitsOnly = /[1234567890]/g;
    var integerOnly = /[0-9\.]/g;
    var alphaOnly = /[A-Za-z]/g;
    var usernameOnly = /[0-9A-Za-z\._-]/g;

    function restrictInput(myfield, e, restrictionType, checkdot){
        if (!e) var e = window.event
        if (e.keyCode) code = e.keyCode;
        else if (e.which) code = e.which;
        var character = String.fromCharCode(code);

        // if user pressed esc... remove focus from field...
        if (code==27) { this.blur(); return false; }

        // ignore if the user presses other keys
        // strange because code: 39 is the down key AND ' key...
        // and DEL also equals .
        if (!e.ctrlKey && code!=9 && code!=8 && code!=36 && code!=37 && code!=38 && (code!=39 || (code==39 && character=="'")) && code!=40) {
            if (character.match(restrictionType)) {
                if(checkdot == "checkdot"){
                    return !isNaN(myfield.value.toString() + character);
                } else {
                    return true;
                }
            } else {
                return false;
            }
        }
    }
</script>

Different usage methods would be:

<!-- To accept only alphabets -->
<input type="text" onkeypress="return restrictInput(this, event, alphaOnly);">
<!-- To accept only numbers without dot -->
<input type="text" onkeypress="return restrictInput(this, event, digitsOnly);">
<!-- To accept only numbers and dot -->
<input type="text" onkeypress="return restrictInput(this, event, integerOnly);">
<!-- To accept only numbers and only one dot -->
<input type="text" onkeypress="return restrictInput(this, event, integerOnly, 'checkdot');">
<!-- To accept only characters for a username field -->
<input type="text" onkeypress="return restrictInput(this, event, usernameOnly);">
Nirmal