Javascript - testing for non-numeric text input [duplicate] - javascript

This question already has answers here:
HTML text input allow only numeric input
(78 answers)
Closed 6 years ago.
I have a text input for a calculator that is already set up to only accept numbers, and I want to allow for both positive and negative integers, but when the input is used, I want to disallow + and - to be entered. Instead, I want to have those inputs cause operations to be performed.
display.keypress(function() {
if (temp === 0 && $(this).val().isInteger()) {
temp = $(this).val().toString();
} else if ($(this).val().isSafeInteger()) {
temp += $(this).val().toString();
}
});

In order to not allow the user to input anything but numbers, you have to substitute the input's onkeypress event with a function that returns true if the key is valid or false if it isn't. This function is called with a parameter event that has information about the key pressed, so you can read it and check what key was pressed.
But to limit it to numbers and + and - signs it's not enough. You do want your user to be able to delete things inside with backspace and delete, use the arrows and home/end. So you have to consider this as well. So you have to check these keys also.
But this explanation makes it seem more difficult than actually is. I made an example that makes things clearer:
function sumSubtractionFunction(oper) {
console.log(oper);
}
document.getElementById('display').onkeypress = function(event) {
// first we check if + or - were pressed and call the function in that case
if (['+', '-'].indexOf(event.key) > -1) {
sumSubtractionFunction(event.key);
return false;
};
// then we check if the key is one that should be allowed
return ([8, 35, 36, 37, 38, 39, 40, 46].indexOf(event.keyCode) > -1)
|| (Number.isInteger(Number(event.key)));
};
<input type="text" id="display"/>
Key codes:
8 -> backspace
35 -> home
36 -> end
37-40 -> arrows
46 -> delete

This might be the answer:
const isInteger = text => /[+-]?\d+/.test(text)
const data = ['1', '-1', '0.2', '-0,2']
for (let num of data){
console.log(`${num} ${isInteger(num)}`)
}
You can also try this:
const isNumber = text => /[+-]?\d+[,.]?\d*/.test(text)
const data = ['1', '-1', '0.2', '-0,2']
for (let num of data){
console.log(`${num} ${isNumber(num)}`)
}

I think this might be what you are asking for. I set a boolean to see if one of the operators were used, then I strip it out and finally sanitize the input; ready for a function to handle the operation.
var numberInput = document.getElementById('numberInput');
numberInput.addEventListener('input', function(){
var add = false;
var subtract = false;
if(this.value.indexOf('+') >= 0) add = true;
if(this.value.indexOf('-') >= 0) subtract = true;
if(isNaN(this.value.slice(-1))) this.value = this.value.slice(0, -1);
if(add) addOperation();
if(subtract) subtractOperation();
});
function addOperation(){
console.log('add!');
}
function subtractOperation(){
console.log('subtract!');
}
<input type="text" id="numberInput"/>

Related

How do I prevent the input of a number like 2.2.2 in my calculator?

I have been working on a simple JS calculator using an OOP approach. I am struggling to create a fix that prevents the input of extra decimals. For example, a user can input 3.2.1.5. Ideally, this calculator would display the entire expression on the digital calculator screen before solving it and returning the result. With this in mind, simply preventing a user from adding a second decimal would prevent them from adding(or whatever operator they may choose) multiple decimals together. I have considered using .split() and .join() on operators in the input, but it is beginning to get convoluted as there are multiple operators to consider. Ideally, I want to avoid regex.
const keys = document.querySelector('.calc-buttons');
keys.addEventListener('click', event => {
const {target} = event
const {value} = target
if(!target.matches('button')){
return
}else{
calculator.parseInput(value)
//console.log(value)
}
})
const calculator = {
displayText: '0',
prevTotal: null,
parseInput(value){
//have any of the special buttons(AC, decimal, =) been clicked?
switch(value){
case '=':
//calculate answer
this.calcAnswer(this.displayText)
break
case 'AC':
//clear screen & stored values
this.clearAll()
break
case '.':
//create decimal
if(this.displayText == 0){
//pass'0.'
this.addText('0.')
}else{
//add value to text string
this.addText(value)
}
break
default:
//add value to text string
this.addText(value)
break
}
},
addText(value){
if(this.displayText == '0'){
this.displayText = ''
}else if(this.prevTotal !== null){
this.displayText = this.prevTotal
this.prevTotal = null
}
//check if previous input is a number
if(isNaN(+(value)) && isNaN(+(this.displayText))){
if(isNaN(this.displayText.slice(-1))){
return
}
}else if(value == '.' && this.displayText.slice(-1) == '.'){
return
}
this.displayText += value
//output display text to screen
this.outputText(this.displayText)
},
outputText(text){
document.querySelector('.screen').value = text
},
calcAnswer(equation){
let result = Function("return " + equation)()
this.outputText(result)
//console.log(equation)
//console.log(result)
this.prevTotal = result
},
clearAll(){
this.displayText = '0',
this.prevTotal = null
this.outputText(this.displayText)
}
}
Functions are based on StepUp's answer (which is wrong AFAIK; it should be .length > 2 but I can't comment yet)
const hasManySymbols = (str, symbol) => {
const firstIndex = str.indexOf(symbol) // find the first occurrence of the symbol
if(firstIndex == -1) return false // if there is no first occurrence there are not many symbols
return str.indexOf(symbol, firstIndex + 1) != -1 // whether or not there is a second occurrence
}
const validate = str => hasManySymbols(str, '.') ? 'invalid input' : 'valid input'
console.log(validate('1.23')) // "valid input"
console.log(validate('1.2.3')) // "invalid input"
I'm not sure if this is faster or slower but it should theoretically be faster I guess.
You can create a simple function to avoid repetition of code and hiding unnecessary details in functions. In addition, it helps to reduce convolution.
So create a function which will check eligibility of input and based on result just notify user or remove last incorrect character.
The sketch of function could like this:
const hasManySigns = (str, sign) => str.split(sign).length > 2
An example:
const hasManySigns = (str, sign) => str.split(sign).length > 2
let foo = '1.2.3'
const validate = str => hasManySigns(str, '.') ? 'incorrect input' : 'correct input'
console.log(validate(foo))

How to create mask for a float type input in ES6?

The rule of input is simple:
Calculation of student grade ...
The inserted notes must go from 0.0 to 10.0 ...
The user can also enter the "f" character to say that the student was missing ...
I was able to block the characters and use the regex to generate the "POINT".
What are the problems:
Input is not generating the regex correctly, I need to enter 3 characters instead of two for it to insert the point
When entering the character f it should block the digit of numbers and vice versa if it enters a number first
It is letting you enter more than 3 characters in the input, I know this is in the input attribute, however I left it as 3 to be able to insert the point.
Functions:
blockCharactersTwo(_event){
let keyPressed = _event.charCode;
(keyPressed >= 48 && keyPressed <= 57 || keyPressed === 46 || keyPressed === 102) ? null : _event.preventDefault();
}
convertToDecimal(_element){
_element.value = _element.value.replace(/(\d{1})(\d{1,2})$/,"$1.$2") // Insere o PONTO ANTES dos ĂšLTIMOS 2 digitos
}
input and output sample:
1) 80 => 8.0
2) 01 => 0.1
3) number => block caracter "F"
4) "f" => block number
5) "f" => if you type "f" do not enter any more characters and not even "f".
I would do this with a handler for the keydown event, and a separate one for reformatting, to make it easier. The regex /^([fF]{1}|\d{1}\.\d{1}|10\.00?)$/ on regex101.com shows how it works. The allNumbersRe expression just looks for the correct pattern for three numbers.
The trick here is that there is no way to prevent them from entering a value > 10.0, if you want to be able to allow them to enter 100 and format it as 10.0, since the number 100 > 10.0. So, I split the formatting out of the keydown handler and added a blur handler to do the formatting. It also validates that the formatted number is less than or equal to 10.0. Here I'm using HTML5 constraint validation for ease of implementation.
Another thing of note is that I'm using KeyboardEvent.key, which is a relatively new addition to the standard. It will return strings like "Delete" and "Backspace" for keys that produce non-printable characters. In this case, I'm assuming that any keys that do that are okay to allow (you presumably want to be able to delete the value).
document.querySelector('.grade').addEventListener('keydown', function (e) {
const char = e.key;
let newValue = e.target.value;
if (char.length > 1) {
return true;
} else {
newValue += char;
}
const perfectRegex = /^([fF]{1}|\d{1}\.\d{1,2}|10\.00?)$/;
const allNumbersRe = /^(\d{1})(\d{1,2})$/;
const numbersAndDecRe = /^[\d\.]{1,4}$/;
if (!perfectRegex.test(newValue) &&
!allNumbersRe.test(newValue) &&
!numbersAndDecRe.test(newValue) &&
newValue.length > 0) {
e.preventDefault();
}
});
document.querySelector('.grade').addEventListener('blur', function (e) {
const tenRe = /^100$/;
const allNumbersRe = /^(\d{1})(\d{1,2})$/;
const newValue = e.target.value;
e.target.setCustomValidity("");
if (tenRe.test(newValue)) {
e.target.value = "10.0";
} else if (allNumbersRe.test(newValue)) {
e.target.value = newValue.replace(allNumbersRe, "$1.$2");
}
if (parseFloat(e.target.value) > 10.0) {
e.target.setCustomValidity("The value cannot be more than 10.0");
e.preventDefault();
}
});
input:invalid { border-color: red; }
<input type="text" class="grade" maxlength="4">

Don't allow the user to enter numbers greater than 12

I have an HTML textbox as:
<input style="width: 13%; height: 25%" name="txthour" id="txthour" onkeypress="return isNumberKey(event)">
I want user to stop if they enter a number greater than 12.
When the user has entered 1, I don't want to them to enter the number 3, this will prevent the number becoming 13 (which is greater than 12).
I am dong this in Javascript as:
function isNumberKey(e) {
if (isNaN($("#txthour").val()))
{
alert("Enter only numbers");
}
if ($("#txthour").val() > 12) {
e.cancel;
}
}
But it's not cancelling the text if it enters 13.
Your first problem with your code is that you are binding it on keypress. That means $("#txthour").val() will not be updated before your event.
You need to know which character the user has pressed. There is a function for that: String.fromCharCode();.
To get the current character, you can use this:
var currentChar = parseInt(String.fromCharCode(e.keyCode), 10);
then you need to check if it is a number:
if(!isNaN(currentChar))
Then you need to concatenate that character to your input:
var nextValue = $("#txthour").val() + currentChar; //It's a string concatenation, not an addition
Parse the new value and check if it's less than or equal to 12. If all of these condition matches, return true.
Final code :
function isNumberKey(e) {
var currentChar = parseInt(String.fromCharCode(e.keyCode), 10);
if(!isNaN(currentChar)){
var nextValue = $("#txthour").val() + currentChar; //It's a string concatenation, not an addition
if(parseInt(nextValue, 10) <= 12) return true;
}
return false;
}
http://jsfiddle.net/6X9Yq/
Edit
To allow the press of the enter key, you need to check if the keycode is 13 :
function isNumberKey(e) {
if(e.keyCode === 13) return true;
var currentChar = parseInt(String.fromCharCode(e.keyCode), 10);
if(!isNaN(currentChar)){
var nextValue = $("#txthour").val() + currentChar; //It's a string concatenation, not an addition
if(parseInt(nextValue, 10) <= 12) return true;
}
return false;
}
Try this instead:
function isNumberKey(e)
{
var exString = $('#txthour').val();
var newString = exString + String.fromCharCode(e.keyCode);
if (isNaN(newString))
{
alert("Enter only numbers");
}
if (newString > 12)
{
e.preventDefault();
}
}
The reason your original code doesn't work is because when the keydown event is called, the value of the text box hasn't been set yet. The code above figures out what the value will be based on your keystroke, and then checks to see if the future value will be > 12. If so, then the preventDefault() call cancels your input.
jQuery solution that:
1) Checks to make sure the user only inputs numbers.
2) Makes sure the number entered is 12 or lower.
3) Alerts the user based on the criteria they're not meeting, and clears the input field.
4) Also accounts for a user pasting something into the field.
$('#txthour').on('paste input', function () {
var number = $(this).val()
if (isNaN(number)) {
alert("Enter only numbers.");
$(this).val('');
}
if (number > 12) {
alert("Value entered must be 12 or lower.");
$(this).val('');
}
});
FIDDLE
$( "#txthour" ).keyup(function() {
if($( "#txthour" ).val() > 12)
{
$( "#txthour" ).val("12");
}
});
http://jsfiddle.net/5tjdL/
The problem:
When the user types a value and you are listening to the onkeypress event, you want to be able to see what the resulting value would be so that you can compare that new value to some other value and then determine if you want to block that input via event.preventDefault() method.
Heres my solution:
1) calculate the "true" new value(now unlike most answers that were previously written that make a huge erroneous assumption "My user will only type a value at the very end of the input field"), I will take into consideration the fact that a user can actually select existing input and overwrite it...ie [before key press] inputField = "12345", user selects "12345" and presses the key for "5", so that would mean that the new value is "5", or if the user selected "234" and pressed the key for "5", the resulting value would be "155".
2) once you have the final "true" value, you can now use the isNaN() method to test if the final value is a valid number or you could just pass the final value to your own method to make whatever comparison you need and decide stop the event by calling event.preventDefault() method. here's a sample code for achieving that.
$(document).keypress(function(event)
{
//this is just a container object for readability purposes
let eventData = {
element: null,
userinput: "",
fieldname: "",
fieldValue: null,
selectionStart: -1,
selectionEnd: -1
}
eventData.fieldName = event.target.id;
eventData.element = document.getElementById(eventData.fieldName);
eventData.fieldValue = element.value; //holds the value before modification
eventData.input = String.fromCharCode(event.keyCode); //what ever the user typed!
eventData.selectionStart = event.target.selectionStart;//this records
eventData.selectionEnd = event.target.selectionEnd;//the user selection if any
let finalValue = getFinalValue(eventData);
if(!isNaN(finalValue)){
//the final value is a number and can be compared to another number!
alert("we have a number! you may proceed");
}else {
//stop right there mister!
alert("You shall not pass!");
event.preventDefault();//user input was blocked!
}
}); // this here marks the end of the onkeypress method,
// and now getFinalValue(eventData) method below...
function getFinalValue(eventData){
let finalValue = eventData.fieldValue.substring(0,eventData.selectionStart) +
eventData.input + eventData.fieldValue.substring(eventData.selectionEnd);
return finalValue;
}//end of the getFinalValue() method

Javascript Regex to limit Text Field to only Numbers (Must allow non-printable keys)

I have received PHP/JS code from previous developer and I need to add number validation to a Mobile Number field. I already have the HTML validation in place but I need to add that if someone presses an invalid key, that it doesn't get displayed only to highlight the field later in red because it contains invalid input.
I've seen many regex's used and tried them but they had an either/or effect from what I need which is: If a letter or special character is entered, do not accept and do not display, all other input (digits, keys) is accepted (I need the invalid character not be displayed at all, not displayed and then erased). The regex that is working the most now is this:
function filterNonDigits(evt)
{
var event = evt || window.event;
var keyentered = event.keyCode || event.which;
keyentered = String.fromCharCode(keyentered);
//var regex1 = /[0-9]|\./;
var regex2 = /^[a-zA-Z.,;:|\\\/~!##$%^&*_-{}\[\]()`"'<>?\s]+$/;
if( regex2.test(keyentered) ) {
event.returnValue = false;
if(event.preventDefault) event.preventDefault();
}
When I used the commented regex1 (with the IF condition reversed), naturally it limited input to only digits thus preventing all keys such as Delete, BackSpace, etc. When using regex2, I still can't press Delete or the digits from the numpad.
So my question is, can the above code be modified to accept only digits but also allow keys? Another important point is that I need a method that doesn't use keycodes (8, 24 etc) for those key, in order to make sure all keyboard types can be used.
New Update:
So my solution is as follows: If the "oninput" property exists, I use the solution provided by Ehtesham and if it doesn't, the backup uses the solution provided by Rohan Kumar. So it's something like this:
if (obj.hasOwnProperty('oninput') || ('oninput' in obj))
{
$('#mobileno').on('input', function (event) {
this.value = this.value.replace(/[^0-9]/g, '');
});
}
else
{
$('#mobileno').on('keypress',function(e){
var deleteCode = 8; var backspaceCode = 46;
var key = e.which;
if ((key>=48 && key<=57) || key === deleteCode || key === backspaceCode || (key>=37 && key<=40) || key===0)
{
character = String.fromCharCode(key);
if( character != '.' && character != '%' && character != '&' && character != '(' && character != '\'' )
{
return true;
}
else { return false; }
}
else { return false; }
});
}
Thanks.
The best method here is to use input event which handles all your concerns. It is supported in all modern browsers. With jQuery you can do like following. Handles all cases pasting the value with mouse/keyboard backspace etc.
$('.numeric').on('input', function (event) {
this.value = this.value.replace(/[^0-9]/g, '');
});
See it here
You can check if input event is supported by checking if the input has this property if not you can use onkeyup for older browsers.
if (inputElement.hasOwnProperty('oninput')) {
// bind input
} else {
// bind onkeyup
}
A nice solution is described in a previous post:
jQuery('.numbersOnly').keyup(function () {
this.value = this.value.replace(/[^0-9\.]/g,'');
});
Try it like,
CSS
.error{border:1px solid #F00;}
SCRIPT
$('#key').on('keydown',function(e){
var deleteKeyCode = 8;
var backspaceKeyCode = 46;
if ((e.which>=48 && e.which<=57) ||
(e.which>=96 && e.which<=105) || // for num pad numeric keys
e.which === deleteKeyCode || // for delete key,
e.which === backspaceKeyCode) // for backspace
// you can add code for left,right arrow keys
{
$(this).removeClass('error');
return true;
}
else
{
$(this).addClass('error');
return false;
}
});
Fiddle: http://jsfiddle.net/PueS2/
Instead of checking for the event keyCode, why don't you just check for changes inside the actual input and then filter out non-numbers?
This example uses keyup so that it can read what was actually entered, which means the character is briefly displayed and then removed, but hopefully you get my gist. It might even give the user feedback that the character is not allowed. Either way I think this is the easiest setup, let me know if you need more help fleshing this out.
function filterNonDigits(evt)
{
var event = evt || window.event;
var val = event.target.value;
var filtered = val.replace(/[^0-9]/g, '');
if(filtered !== val) {
event.target.value = filtered;
event.target.className += " error";
}
}
http://jsfiddle.net/mEvSV/1/
(jquery used solely to easily bind the keyup function, you won't need it for your actual script)
/\d/ is equivalent to the above described /[0-9]/. src: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-digit
This is a bit more concise...
this.value = this.value.replace(/\D/gm, '');

js backspace and counting how many digits

i have this code for counting how many digits where entered
var tnnod=0;
function telephone(e) {
if (tnnod<10) {
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)) {
tnnod+=1;
return true;
}
else if (keychar == "-") {
return true;
}
else
return false;
}
else
return false
}
but how do i remove 1 from the counter each time the backspace was hitted and the char that was deleted was a digit and not "-"
i have tried getting the key == 8 to do something but hitting the backspace doesn't really return anything for some reason
what can be the problem?
You don't have to detect specifically the backspace keypress. Try this:
var tn_count = 0;
function telephone(ev) {
var el = document.getElementById("telephone_number");
if(tn_count < 10) {
var key, keychar;
if(window.event) {
key = window.event.keyCode;
} else {
key = ev.which;
}
keychar = String.fromCharCode(key);
}
if(!keychar.match(/\d|-/)) { // only allow digits or "-"
return false;
}
// clean up any non-digit chars that get in here somehow
el.value = el.value.replace(/[A-Za-z]+/, '');
tn_count = el.value.replace("-",'').length; // get the digit length
return true;
}
The basic difference here is that instead of adding 1 every time the key is pressed, just updated tn_count to be the total count of all digit characters in the field. You can probably do some more cleanup just to be safe, but this should get you started.
I think it's a bad idea to count keystrokes for something like that. We're talking about input into a text field, right? What will you do if the user does a paste of some string from the clipboard? What if he uses the mouse to mark some text and delete it? Replace it with one character?
I think it would make a lot more sense to just look at the text from the text field and (if necessary) do some fiddling to ensure proper syntax. Let the user enter whatever he wants, if you find garbage characters you can just replace the text with one that doesn't have those characters. You can also trim the field at this time (no leading or trailing spaces). Also, keeping accurate track of the length becomes as easy as asking for the length of the string returned from the field.
A few thoughts -
Would it be possible to use 3 fields instead of 1? Then you could add the dashes later.
If you want to use your current method, you might keep a counter of the dashes that have been typed. Then, on each key stroke, check to see how many dashes are left. If it's different than the previous count, you know they've deleted the dashes.
I think it needs to be a bit more robust. What if they put a dash in an odd place within the string?
You could also prevent the user from entering all non-numeric characters and insert the dashes at each point of separation. So, insert a dash after 3 and 6 numbers as they are typing.
Could you just count the length of the string and use that value? Something like the following:
function getLen(el) {
return el.value.replace('-', '').length;
}
alert(getLen(document.getElementById('telephone_number')));

Categories

Resources