How to handle floats and decimal separators with html5 input type number

后端 未结 10 601
情话喂你
情话喂你 2020-11-27 11:15

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

相关标签:
10条回答
  • 2020-11-27 11:25

    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:

    1. Using the pattern attribute

    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..

    2. JavaScript validation

    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.

    3. Disable browser validation ##

    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 />
    

    4. Combination..?

    <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."/>
    
    0 讨论(0)
  • 2020-11-27 11:26

    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

    0 讨论(0)
  • 2020-11-27 11:34

    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).

    My Solution

    I added a keyup event Handler to the form input and tracked the state and set the value once it comes valid again.

    Pure JS Snippet JSFIDDLE

    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>

    Angular 9 Snippet

    @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">

    0 讨论(0)
  • 2020-11-27 11:37

    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:

    • Mobile users will see their phone keyboard which may be different than the number keyboard.
    • Even worse the phone keyboard may not even have a key for a comma.

    For my use case I only had to:

    • Display the initial value with a comma (firefox strips it out for type=number)
    • Not fail html5 validation (if there is a comma)
    • Have the field read exactly as input (with a possible comma)

    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.

    0 讨论(0)
  • 2020-11-27 11:42

    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:

    • jsFiddle

    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.

    0 讨论(0)
  • 2020-11-27 11:44

    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.

    0 讨论(0)
提交回复
热议问题