Input type number “only numeric value” validation

后端 未结 5 1773
耶瑟儿~
耶瑟儿~ 2021-02-03 17:43

How can I validate an input of type=\"number\" to only be valid if the value is numeric or null using only Reactive Forms (no directives)?
Only numbers

5条回答
  •  萌比男神i
    2021-02-03 18:01

    I had a similar problem, too: I wanted numbers and null on an input field that is not required. Worked through a number of different variations. I finally settled on this one, which seems to do the trick. You place a Directive, ntvFormValidity, on any form control that has native invalidity and that doesn't swizzle that invalid state into ng-invalid.

    Sample use:

    Directive definition:

    import { Directive, Host, Self, ElementRef, AfterViewInit } from '@angular/core';
    import { FormControlName, FormControl, Validators } from '@angular/forms';
    
    @Directive({
      selector: '[ntvFormValidity]'
    })
    export class NtvFormControlValidityDirective implements AfterViewInit {
    
      constructor(@Host() private cn: FormControlName, @Host() private el: ElementRef) { }
    
      /* 
      - Angular doesn't fire "change" events for invalid 
      - We have to check the DOM object for browser native invalid state
      - Add custom validator that checks native invalidity
      */
      ngAfterViewInit() {
        var control: FormControl = this.cn.control;
    
        // Bridge native invalid to ng-invalid via Validators
        const ntvValidator = () => !this.el.nativeElement.validity.valid ? { error: "invalid" } : null;
        const v_fn = control.validator;
    
        control.setValidators(v_fn ? Validators.compose([v_fn, ntvValidator]) : ntvValidator);
        setTimeout(()=>control.updateValueAndValidity(), 0);
      }
    }
    

    The challenge was to get the ElementRef from the FormControl so that I could examine it. I know there's @ViewChild, but I didn't want to have to annotate each numeric input field with an ID and pass it to something else. So, I built a Directive which can ask for the ElementRef.

    On Safari, for the HTML example above, Angular marks the form control invalid on inputs like "abc".

    I think if I were to do this over, I'd probably build my own CVA for numeric input fields as that would provide even more control and make for a simple html.

    Something like this:

    PS: If there's a better way to grab the FormControl for the directive, I'm guessing with Dependency Injection and providers on the declaration, please let me know so I can update my Directive (and this answer).

提交回复
热议问题