1

So basically, I have a large form with more than 50 text inputs.

I am applying a function via onKeyPress to all of them to make sure that they are numbers only with the use of one decimal point.

This is my regex function:

function pointAndNumbersOnly(inputString)
{
    return inputString.match(/^[0-9]*\.?[0-9]*$/);
}

This is an example of one of my text inputs:

<input type="text" pattern="\d*" class="form-main" name="priceGST" id="priceGST" placeholder="Enter GST without % sign" value="10" onkeypress="return pointAndNumbersOnly(this.id);">

What is my mistake here?

PS. I am receiving no errors in my console.

hwnd
  • 65,661
  • 4
  • 77
  • 114
Fizzix
  • 20,849
  • 34
  • 100
  • 160
  • 1
    You're passing `this.id` to the function, not `this.value`. – Barmar Nov 16 '13 at 00:37
  • 1
    Also `.match()` returns an array of matched strings. It's probably not what you want, but it's not really clear what you're up to here. – Pointy Nov 16 '13 at 00:38
  • @Barmar - when I use `this.value` instead of `this.id`, I still get no luck. Nothing happens, and no errors are returned to the console. – Fizzix Nov 16 '13 at 00:41
  • @Pointy - I am applying the `onKeyPress` function to each individual text input I have. So yes, you are right, I do not want to return an array. What is the alternative? – Fizzix Nov 16 '13 at 00:42
  • @fizzix: If you just want to validate the input use `RegExp.prototype.test` that will return `true|false` – elclanrs Nov 16 '13 at 00:44
  • @Pointy It returns an array of matched strings, or null if there are no matches, so it can still be used in a boolean context. – Barmar Nov 16 '13 at 00:45
  • @Barmar - Don't really need to to be boolean. Users should never be able to enter any other characters besides 1 dot point and numbers. – Fizzix Nov 16 '13 at 00:46
  • @elclanrs - Didn't work, and returned no errors. – Fizzix Nov 16 '13 at 00:47
  • I think the problem is you're using the wrong event. `keypress` occurs before the value is updated. You need to use `keyup`. – Barmar Nov 16 '13 at 00:48
  • @Barmar it doesn't return `false`, it returns `null`. I don't know if that is equivalent to returning `false` in an event handler. – Pointy Nov 16 '13 at 00:49
  • @Barmar - Very true, and I have added that in. Although, still no change. I really think there is a problem with `return inputString.match(/^[0-9]*\.?[0-9]*$/);` – Fizzix Nov 16 '13 at 00:50
  • @fizzix Have you tried Pointy's recommendation to use `.test` instead of `.match`? – Barmar Nov 16 '13 at 00:51
  • @Barmar - `Uncaught TypeError: Object 10 has no method 'test' ` While `10` is the value I am entering into the text input. – Fizzix Nov 16 '13 at 00:53
  • @Barmar - Would you like me to create a JSfiddle to make this easier for you? – Fizzix Nov 16 '13 at 00:54
  • 1
    You're not using `.test` correctly. It's `regex.test(string)`, not `string.test(regex)`. – Barmar Nov 16 '13 at 00:56

4 Answers4

1

Let's begin with the usage of your regex, you should be doing it like this:

var inputString = document.getElementById('priceGST').value;
var regex = /^[0-9]*\.?[0-9]*$/;
var valid = regex.test(inputString);

So this should work just fine for you:

function pointAndNumbersOnly(inputString)
{
    var regex = /^[0-9]*\.?[0-9]*$/;
    var valid = regex.test(inputString);
    return valid;
}
var inputString = document.getElementById('priceGST').value;
var valid = pointAndNumbersOnly(inputString);

There are other options though:

function pointAndNumbersOnly(inputString)
{
    var regex = /^[0-9]*\.?[0-9]*$/;
    var valid = regex.exec(inputString);
    return valid;
}
var inputString = document.getElementById('priceGST').value;
var valid = pointAndNumbersOnly(inputString);

Let's make your function even better by only requiring elements to be pushed down, not their values:

function pointAndNumbersOnly(inputElement)
{
    var inputString = inputElement.value;
    var regex = /^[0-9]*\.?[0-9]*$/;
    var valid = regex.test(inputString);
    return valid;
}
var inputElement = document.getElementById('priceGST');
var valid = pointAndNumbersOnly(inputElement);

Now another matter:

Using html-attributes such as onkeypress, click, etc... is bad practice since we want to separate our HTMLand JavaScript. Besides, onkeypress is a problem maker to begin with because it doesn't always do what you think it does. It's better to use change, keyup and keydown to detect changes.

Instead of using onkeypress="return pointAndNumbersOnly(this.id);we want to use event delegation to detect changes in the dom, using our new change events:

function pointAndNumbersOnly(inputElement)
{
    var inputString = inputElement.value;
    var regex = /^[0-9]*\.?[0-9]*$/;
    var valid = regex.test(inputString);
    return valid;
}

inputElement.addEventListener("change, keyup, keydown", function(e)
{
    var inputElement = document.getElementById('priceGST'); // Makes more sense to use this
    var valid = pointAndNumbersOnly(inputElement );
    // ...
});

You can also add event listeners to a set of elements by referencing to their class.

Finally:

Make sure the JavaScript is defined AFTER your DOM is ready, that is, make sure the JavaScript is added at the bottom of your body so that the HTML exists OR you have functionality such as jQuery's .ready function, that detects when the DOM is loaded and the JavaScript within is allowed to execute, otherwise it won't know the HTML ids' such as id="priceGST".

If you define your JavaScript and try to reference HTML ids' then you'll see that they are undefined, or just null, because they don't exist at that specific point.

Jonast92
  • 4,861
  • 1
  • 14
  • 30
  • Sorry, but that confused the hell out of me. Are you able to build it into one function? – Fizzix Nov 16 '13 at 01:00
  • 1
    @fizzix: It's good advice, you should add the event handlers in JavaScript not in the markup. – elclanrs Nov 16 '13 at 01:05
  • Returns this error upon page load: `Uncaught TypeError: Cannot read property 'value' of null ` – Fizzix Nov 16 '13 at 01:07
  • Much clearer, thanks :) Unfortunately, your code returns an error of `Uncaught ReferenceError: priceInput is not defined` – Fizzix Nov 16 '13 at 01:18
  • 1
    @fizzix: Try to understand what this answer is all about, a copy/paste won't solve your issues... Those errors you're getting are irrelevant, `inputElement` or `priceInput`, it's just a variable name. Take the advice of querying the DOM. – elclanrs Nov 16 '13 at 01:21
  • Take a better look at the code, I'm not using priceInput there anymore. – Jonast92 Nov 16 '13 at 01:28
  • 1
    @Jonast92: Last piece of code `priceInput.addEventListener...` – elclanrs Nov 16 '13 at 01:29
  • Sorry, I was, It's suppose to be `inputElement.addEventListener`, defined above. Try it now, but also try to understand what's going on. – Jonast92 Nov 16 '13 at 01:46
1

After seeing all other answers and looking into your problem I think this is what you want.

HTML:

<input type="text" pattern="\d*" class="form-main" name="priceGST" id="priceGST" placeholder="Enter GST without % sign" value="10"/>

Attach the events in JavaScript, and prevent the default behavior if the input is not valid. By using keypress event you can read the current character accurately, append it to the value that was read (which excludes the character you just typed) and then pass the validation.

JavaScript:

function isValidNumber(str) {
  return /^\d*\.?\d*$/.test(str);
}

document.getElementById('priceGST').addEventListener('keypress', function(e) {
  var char = String.fromCharCode(e.which);
  if (! isValidNumber(this.value + char)) {
    e.preventDefault();
  }
});

DEMO: http://jsbin.com/oCobAfUJ/1/edit

elclanrs
  • 85,039
  • 19
  • 126
  • 159
  • Upon page load, I get this error in my console: `Uncaught TypeError: Cannot call method 'addEventListener' of null ` – Fizzix Nov 16 '13 at 01:13
  • But you're on the right track, that is exactly what I am after. Odd that it works in the demo... but not in my code. Could there perhaps be some conflicting code? Can elements have two event listeners? – Fizzix Nov 16 '13 at 01:14
  • But my HTML input clearly has the id of `priceGST`, as stated in my question. – Fizzix Nov 16 '13 at 01:16
  • 1
    Well, that's what the error means, `document.getElementById('priceGST')` returned `null`, which means that the element doesn't exist. If it works on the demo and not your code, double check again, the issue is clearly somewhere in your code. – elclanrs Nov 16 '13 at 01:18
  • Worked like a charm once I called it before the closing `body` tag. Thanks for your help :) – Fizzix Nov 16 '13 at 01:22
  • Since this is made to be applied to more than 50 text inputs, would I need to create a new `event listener` for each element? – Fizzix Nov 16 '13 at 01:23
  • Not necessarily, read on "event delegation", check out this question http://stackoverflow.com/questions/1687296/what-is-dom-event-delegation – elclanrs Nov 16 '13 at 01:24
  • Any chance of an example in my case? – Fizzix Nov 16 '13 at 01:55
0

Change the way you pass the parameter to the pointAndNumbersOnly function and it should work:

onkeypress="return pointAndNumbersOnly(this.val());"

Edit: as mentioned, the above solution is JQuery. With Javascript is should be:

onkeypress="return pointAndNumbersOnly(this.value);"
Xar
  • 5,913
  • 12
  • 47
  • 67
  • 3
    `.val()` is jQuery, not plain Javascript. – Barmar Nov 16 '13 at 00:38
  • Returns this error to the console: `Uncaught TypeError: Object # has no method 'val' ` – Fizzix Nov 16 '13 at 00:40
  • @fizzix That's because it's jQuery, not Javascript, like I said above. And it's not even correct jQuery, which would be `$(this).val()`. – Barmar Nov 16 '13 at 00:43
  • Exactly, that was JQuery. I have edited my answer with the javascript version. – Xar Nov 16 '13 at 00:44
  • @Xar - Still no luck. I believe that is half the problem fixed, although I think there is still an error for how my regex is called. – Fizzix Nov 16 '13 at 00:44
0

Firstly,use onkeyup instead of onkeypress because when use onkeyup,you can get this.value as what you've just input,and onkeypress will get your input value before.

For example,the inputbox has current value 10 and you want to input 101.

onkeyup will get this.value = 101,

onkeypress will get this.value = 10.

As I will do,I will set a preValue,if the current value is invalid,set this.value to preValue.

Just like this:

//html
<input onkeyup="return pointAndNumbersOnly(this);" type="text" pattern="\d*" class="form-main" name="priceGST" id="priceGST" placeholder="Enter GST without % sign" value="10">

//js
function pointAndNumbersOnly(obj){
    var key = 'price'+obj.id;
    //.2 will be valid here. If not,use /^[0-9]+\.?[0-9]*$|^$/ instead
    if(obj.value.match(/^[0-9]*\.?[0-9]*$/) !== null) {
        window[key] = obj.value;
        return true;
    }else {
        obj.value = window[key];
        return false;
    }
}
Zjmainstay
  • 123
  • 6