Chrome/Chromium input number value empty when last char is dot - javascript

In Chrome (or other Chromium browser) when I try to get a value of a number input field the value is empty when the last char is a dot (.).
Here is the simplest example I could think of:
<input type="number" oninput="console.log(event.target.value)">
In Chrome when typing for example "123.45" will result in this output:
1
12
123
123.4
123.45
In Firefox I get something more like I would expect:
1
12
123
123
123.4
123.45
Getting valueAsNumber instead of value will result in a NaN if the last char is dot, so no success there either.
Is there a way to get what is is the actual value of the field (or at least the value without the dot) and not something that is already parsed somehow?
UPDATE:
Thanks to #Kaiido I'm a little closer as to why this happens
In my Chrome browser navigator.languages is set to ['en-US', 'en', 'nl'] in Firefox it's set to just ['en-US', 'en']
This explains the difference between the 2 browsers (in my case) and why in Chrome I can use , as well as ..
But I still need a solution for the problem.
The most important thing in my case is that I need a distinction between the field being empty or some other value that somehow can't de parsed to a number. So now the question is more is there a way to get the value of what's actually being types in the field.

Use the 'step' attribute to make it validate and use the locales delimiter.
<input type="number" step="0.01" oninput="console.log(event.target.value)" />
More information:
<input type="number" oninput="console.log('VAL: %s|%s|%s', this.value, this.checkValidity(), this.validationMessage)" step="0.1">
Entering a delimiter not used in the current locale the validity and corresponding message will indicate 'this is not a number', once more digits are entered - up to the limit of precision the step attribute allows - it will parse to valid values again. Your GUI should correspondingly indicate the current validity - if your code requires it to always be usable as a valid number you could save the last value that passed validation, depending on your use case.
Also consider the use of the character "e" which may be cause for a temporary invalid value!

Related

nativeElement.value is NaN if there is a comma

I'm trying to set the number of decimals at 2 in an input. When I type a comma in it, the value becomes NaN so I would like get my number instead of this.
TS
#ViewChild('number') input;
limitNbOfDecimals() {
var regex =
this.form.number.search(/^(\d+(?:[\.\,]\d{0,2})?)$/) == 0
? true
: false;
if (regex == false) {
// Convert the value to a number
var nb: number = +this.input.nativeElement.value;
//set decimals at 2
this.input.nativeElement.value = nb.toFixed(2);
}
}
HTML
<input class="form-control" type="text" [(ngModel)]="form.number"
#number
name="number"
(input)="limitNbOfDecimals()"
/>
EDIT
I manage to add a comma in the number but if I try to add more than 2 decimals after it removes the numbers after the comma like 1,11 -> 1
This isn't a full answer, in the sense of having a total solution, but hopefully helps you get to one (and it's too long for a comment).
The spec at https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number) states:
This specification does not define what user interface user agents
are to use; user agent vendors are encouraged to consider what would
best serve their users' needs. ..... a user agent designed for the
French market might display the value with apostrophes between
thousands and commas before the decimals, and allow the user to enter
a value in that manner, internally converting it to the submission
format described above.
It would seem that the only sure way - if you don't have control over what browsers your users have - of ensuring they can type numbers in the format they are used to in their local setting is to take input as type text and on each keystroke check that they have typed something valid (as you have defined it) and when they submit it convert to a decimal number.
Searching provides code for doing this, depending on exactly what your requirement is for the number formats though you may be better off coding it from scratch.
To add more than 2 decimal values, you need to tell like .toFixed(4) etc..

How can I make a text box in React which allows only numbers or an empty value, which triggers the number keypad on mobile?

There are lots of questions like this on StackOverflow, but none of them captures all of my requirements in the same solution. Any help appreciated.
The problem
In my React app, I need a text box with the following characteristics:
It only allows digits to be entered - no minus signs, decimal places, letters, or anything besides just the digits 0-9.
It automatically brings up the number keypad on iOS and Android
I can further restrict the numbers that should be entered, e.g. only allow 4 digits
Leading zeroes are automatically trimmed, e.g. if a user types 02 it should correct to just 2
It allows an empty textbox, and can differentiate between empty and a value of 0
Current code
https://codepen.io/micahrl/pen/RwGeLmo
This code allows typing non-digits, and will just interpret the value as NaN. For instance, the user can type 2f or asdf and the page will say You typed: NaN.
Additionally, while the page loads initially with an empty text box, the user cannot type something and then delete it back to empty. Attempting to delete all text in the input box places a 0 in the box.
Finally, this code doesn't reliably trim leading zeroes, which causes me particular problems because I want to restrict the number to four digits. Typing 01 will not truncate the leading zero; on some browsers, typing 01111 will result in 1111, which is good enough, while on others, typing 01111 will result in 0111, which is a problem.
What I've tried
Because I have set type="number" on the input element, if there is ever a non-number added to the text box, event.target.value in setNumWrapper will be an empty string. This means I can't differentiate between a true empty string (where the user has deleted all text) and invalid input (where the user has typed a non-number, like asdf).
I could set type="text" on the input element, except that I think I need to set it to number to get the number keypad on mobile OSes like iOS and Android.
With further experimentation, and some help from #Keith in a comment, I've solved almost all my problems.
I've forked the codepen in my question and made these changes in the fork: https://codepen.io/micahrl/pen/GRjwqdO.
Checking input validity
#Keith pointed me to validity.badInput (https://developer.mozilla.org/en-US/docs/Web/API/ValidityState/badInput). With this, I can differentiate between empty input, where a user types something then deletes it, and bad input, where the user attempts to add a non-numeric character.
That means I add this to the beginning of setNumWrapper():
if (event.target.value === "") {
if (event.target.validity.badInput) {
// Set the text box and number to the old value - ignore the bad input
inputRef.current.value = String(num);
setNum(num);
} else {
// The data in the text box was deleted - set everything to empty
inputRef.current.value = "";
setNum(NaN);
}
return;
}
I also have to make an inputRef with useRef(), and set it on the <input> element.
This solves #5 most of #1 (but see below for one remaining minor problem).
Trimming leading zeroes
All I had to do for this was use that inputRef to set the value in the <input> element at the end of setNumWrapper():
inputRef.current.value = String(newNum);
The <input> element's value is always a string anyway, and casting the number to a string removed leading zeroes, if there were any.
Remaining problem: invalid input is allowed if the text box is empty
When the text box is empty, the user can type non-numeric characters into it, and setNumWrapper() doesn't even fire. If you put a console.log() at the top of setNumWrapper(), it won't print anything to the log if the user types a letter, but it will print to the log if the user types a number.
This means I cannot use setNumWrapper() to solve this problem.
However, it's also relatively minor. On mobile, the number keypad comes up, preventing non-numeric input. On the desktop nothing stops the user from typing letters with their keyboard, but for my app, it's clear that only numbers are allowed, so this is good enough for now.
Still, if there's a way to fix this, I'd be curious to hear about it.

AngularJS number input that ignores all keys but numbers

I've been trying to create an input in an AngularJS template and that will only accept whole numbers as input. That is, I don't want it to allow any keys other than 0-9, specifically, I can't stop . from being allowed in the input.
Alexander Puchkov created a directive that achieves this on inputs with type="text" however I want to be able to use type="number" so I can maintain all my other attributes on the field for validation such as min, max, step, etc.
I have an example of this directive not working on a number input here. For example, when type="text" an input of 123. yields a rendering of 123 however when type="number" an input of 123. yeilds 123. since the previous value of 123 is equal when compared numerically.
I'm afraid this simply isn't possible as the following condition is true:
0. == 0
If you perform the following:
setTimeout(() => console.log(element[0].value), 100))
It will always log 0. as 0. This is why ngModelCtrl isnt triggering the parser as no changes are detected.
I would suggest not directly modifying the value of ngModel (as this can also end up leading to users putting in invalid data. ie. pasting 12.00 will resolve to 1200 with your example)
I would add a directive that applies validity depending on if a decimal point is used (technically speaking, typing 0. isn't actually using it. 0.01 is). Set the validity to false if there is a decimal point in the number and display an error message accordingly (via ngMessages). This way the user can correct their own error and can learn from the mistake.

Convert number in javascript produces NAN

I have a text box whose outcome is in Belgium number format like this
<input type="text" name="valeurCatalogue" kendo-numeric-text-box="" k-culture='"fr-BE"' k-spinners="{{false}}" ng-disabled="isValueCatalogDisabled" ng-model="tarifForm.Vehicle.valeurCatalogue" />
Having put the value as 1525,8 the value gets transformed to 1.525,80 which is correct.
Now if I apply Number(1525,8) I get NAN.How to get the number in javascript?
Please note in debug mode I see the value 1525,8 as string.
The problem here is that javascript uses the american way of expressing numbers (as do most programming languages I've encountered). So, 1,5 is not one and a half as you would expect, rather it's not a valid number. Thus when you try to parse it you get NaN (Not a Number). In javascript, the correct way to write said number would be 1.5. If you have 1525,8 the simple way to do this is replace all commas with dots like this:
const numStr = '1525,8';
const replaced = numStr.replace(/,/, '.');
const num = Number(replaced);
If however, your number is 1.525,8 you need to first remove the dots (str.replace(/\./g, '');).

Obtain and check the value of an input text with javascript

I am fairly new with javascript and I need a script to obtain the value of an input text and check that value if it is equal to 0 (zero). If it does then I need an alert message notifying me that the text input is 0. Thanks.
<input id="txtVal" type="text" name="txtVal" value="0" maxlength="10">
The short answer:
if(txVal.value==0) alert('Please enter a number.');
Is not always the best answer:
var v=document.getElementById('txtVal');
v=parseInt(v,10);
if(v<=0) alert('Please enter a positive integer.');
Of course that probably not the best answer either but it does fix a couple of common mistakes.
Although you can refer to an element by using its id as a variable name its not recomended.
The value property of an input (ie txtVal.value) is a string (even if it contains only digits) so if you try to compare it to a number you may get unexpected results. In this case you are comparing it to 0 so problems are less likely but if you ever change your code to compare to another number you will probably run into problems, so its best to make it into an actual number before you do anything with it.
If you want to allow decimals use parseFloat instead.

Categories

Resources