Im building web app which is mainly for mobile browsers. Im using input fields with number type, so (most) mobile browsers invokes only number keyboard for better user exper
According to w3.org the value attribute of the number input is defined as a floating-point number. The syntax of the floating-point number seems to only accept dots as decimal separators.
I've listed a few options below that might be helpful to you:
With the pattern attribute you can specify the allowed format with a regular expression in a HTML5 compatible way. Here you could specify that the comma character is allowed and a helpful feedback message if the pattern fails.
<input type="number" pattern="[0-9]+([,\.][0-9]+)?" name="my-num"
title="The number input must start with a number and use either comma or a dot as a decimal character."/>
Note: Cross-browser support varies a lot. It may be complete, partial or non-existant..
You could try to bind a simple callback to for example the onchange (and/or blur) event that would either replace the comma or validate all together.
Thirdly you could try to use the formnovalidate attribute on the number inputs with the intention of disabling browser validation for that field all together.
<input type="number" formnovalidate />
<input type="number" pattern="[0-9]+([,\.][0-9]+)?"
name="my-num" formnovalidate
title="The number input must start with a number and use either comma or a dot as a decimal character."/>
uses a text type but forces the appearance of the numeric keyboard
<input value="12,4" type="text" inputmode="numeric" pattern="[-+]?[0-9]*[.,]?[0-9]+">
the inputmode tag is the solution
Appearently Browsers still have troubles (although Chrome and Firefox Nightly do fine). I have a hacky approach for the people that really have to use a number field (maybe because of the little arrows that text fields dont have).
I added a keyup
event Handler to the form input and tracked the state and set the value once it comes valid again.
var currentString = '';
var badState = false;
var lastCharacter = null;
document.getElementById("field").addEventListener("keyup",($event) => {
if ($event.target.value && !$event.target.validity.badInput) {
currentString = $event.target.value;
} else if ($event.target.validity.badInput) {
if (badState && lastCharacter && lastCharacter.match(/[\.,]/) && !isNaN(+$event.key)) {
$event.target.value = ((+currentString) + (+$event.key / 10));
badState = false;
} else {
badState = true;
}
}
document.getElementById("number").textContent = $event.target.value;
lastCharacter = $event.key;
});
document.getElementById("field").addEventListener("blur",($event) => {
if (badState) {
$event.target.value = (+currentString);
badState = false;
document.getElementById("number").textContent = $event.target.value;
}
});
#result{
padding: 10px;
background-color: orange;
font-size: 25px;
width: 400px;
margin-top: 10px;
display: inline-block;
}
#field{
padding: 5px;
border-radius: 5px;
border: 1px solid grey;
width: 400px;
}
<input type="number" id="field" keyup="keyUpFunction" step="0.01" placeholder="Field for both comma separators">
<span id="result" >
<span >Current value: </span>
<span id="number"></span>
</span>
@Directive({
selector: '[appFloatHelper]'
})
export class FloatHelperDirective {
private currentString = '';
private badState = false;
private lastCharacter: string = null;
@HostListener("blur", ['$event']) onBlur(event) {
if (this.badState) {
this.model.update.emit((+this.currentString));
this.badState = false;
}
}
constructor(private renderer: Renderer2, private el: ElementRef, private change: ChangeDetectorRef, private zone: NgZone, private model: NgModel) {
this.renderer.listen(this.el.nativeElement, 'keyup', (e: KeyboardEvent) => {
if (el.nativeElement.value && !el.nativeElement.validity.badInput) {
this.currentString = el.nativeElement.value;
} else if (el.nativeElement.validity.badInput) {
if (this.badState && this.lastCharacter && this.lastCharacter.match(/[\.,]/) && !isNaN(+e.key)) {
model.update.emit((+this.currentString) + (+e.key / 10));
el.nativeElement.value = (+this.currentString) + (+e.key / 10);
this.badState = false;
} else {
this.badState = true;
}
}
this.lastCharacter = e.key;
});
}
}
<input type="number" matInput placeholder="Field for both comma separators" appFloatHelper [(ngModel)]="numberModel">
I have not found a perfect solution but the best I could do was to use type="tel" and disable html5 validation (formnovalidate):
<input name="txtTest" type="tel" value="1,200.00" formnovalidate="formnovalidate" />
If the user puts in a comma it will output with the comma in every modern browser i tried (latest FF, IE, edge, opera, chrome, safari desktop, android chrome).
The main problem is:
For my use case I only had to:
If you have a similar requirement this should work for you.
Note: I did not like the support of the pattern attribute. The formnovalidate seems to work much better.
I think what's missing in the answers above is the need to specify a different value for the step
attribute, which has a default value of 1
. If you want the input's validation algorithm to allow floating-point values, specify a step accordingly.
For example, I wanted dollar amounts, so I specified a step like this:
<input type="number" name="price"
pattern="[0-9]+([\.,][0-9]+)?" step="0.01"
title="This should be a number with up to 2 decimal places.">
There's nothing wrong with using jQuery to retrieve the value, but you will find it useful to use the DOM API directly to get the elements's validity.valid
property.
I had a similar issue with the decimal point, but the reason I realized there was an issue was because of the styling that Twitter Bootstrap adds to a number input with an invalid value.
Here's a fiddle demonstrating that the adding of the step
attribute makes it work, and also testing whether the current value is valid:
TL;DR: Set the a step
attribute to a floating-point value, because it defaults to 1
.
NOTE: The comma doesn't validate for me, but I suspect that if I set my OS language/region settings to somewhere that uses a comma as the decimal separator, it would work. *note in note*: that was not the case for OS language/keyboard settings *German* in Ubuntu/Gnome 14.04.
Whether to use comma or period for the decimal separator is entirely up to the browser. The browser makes it decision based on the locale of the operating system or browser, or some browsers take hints from the website. I made a browser comparison chart showing how different browsers support handle different localization methods. Safari being the only browser that handle commas and periods interchangeably.
Basically, you as a web author cannot really control this. Some work-arounds involves using two input fields with integers. This allows every user to input the data as yo expect. Its not particular sexy, but it will work in every case for all users.