Reactive Forms - mark fields as touched

后端 未结 19 1470
旧时难觅i
旧时难觅i 2020-12-04 23:15

I am having trouble finding out how to mark all form\'s fields as touched. The main problem is that if I do not touch fields and try to submit form - validation error in not

相关标签:
19条回答
  • 2020-12-04 23:28

    I completely understand the OP's frustration. I use the following:

    Utility function:

    /**
     * Determines if the given form is valid by touching its controls 
     * and updating their validity.
     * @param formGroup the container of the controls to be checked
     * @returns {boolean} whether or not the form was invalid.
     */
    export function formValid(formGroup: FormGroup): boolean {
      return !Object.keys(formGroup.controls)
        .map(controlName => formGroup.controls[controlName])
        .filter(control => {
          control.markAsTouched();
          control.updateValueAndValidity();
          return !control.valid;
        }).length;
    }
    

    Usage:

    onSubmit() {
      if (!formValid(this.formGroup)) {
        return;
      }
      // ... TODO: logic if form is valid.
    }
    

    Note that this function does not yet cater for nested controls.

    0 讨论(0)
  • 2020-12-04 23:28

    View:

    <button (click)="Submit(yourFormGroup)">Submit</button>   
    

    API

    Submit(form: any) {
      if (form.status === 'INVALID') {
          for (let inner in details.controls) {
               details.get(inner).markAsTouched();
           }
           return false; 
         } 
         // as it return false it breaks js execution and return 
    
    0 讨论(0)
  • 2020-12-04 23:31

    This is the code that I am actually using.

    validateAllFormFields(formGroup: any) {
        // This code also works in IE 11
        Object.keys(formGroup.controls).forEach(field => {
            const control = formGroup.get(field);
    
            if (control instanceof FormControl) {
                control.markAsTouched({ onlySelf: true });
            } else if (control instanceof FormGroup) {               
                this.validateAllFormFields(control);
            } else if (control instanceof FormArray) {  
                this.validateAllFormFields(control);
            }
        });
    }    

    0 讨论(0)
  • 2020-12-04 23:32

    This code works for me:

    markAsRequired(formGroup: FormGroup) {
      if (Reflect.getOwnPropertyDescriptor(formGroup, 'controls')) {
        (<any>Object).values(formGroup.controls).forEach(control => {
          if (control instanceof FormGroup) {
            // FormGroup
            markAsRequired(control);
          }
          // FormControl
          control.markAsTouched();
        });
      }
    }
    
    0 讨论(0)
  • 2020-12-04 23:40

    Looping through the form controls and marking them as touched would also work:

    for(let i in this.form.controls)
        this.form.controls[i].markAsTouched();
    
    0 讨论(0)
  • 2020-12-04 23:40

    A solution without recursion

    For those worried about performance, I've come up with a solution that doesn't use recursion, although it still iterates over all controls in all levels.

     /**
      * Iterates over a FormGroup or FormArray and mark all controls as
      * touched, including its children.
      *
      * @param {(FormGroup | FormArray)} rootControl - Root form
      * group or form array
      * @param {boolean} [visitChildren=true] - Specify whether it should
      * iterate over nested controls
      */
      public markControlsAsTouched(rootControl: FormGroup | FormArray,
        visitChildren: boolean = true) {
    
        let stack: (FormGroup | FormArray)[] = [];
    
        // Stack the root FormGroup or FormArray
        if (rootControl &&
          (rootControl instanceof FormGroup || rootControl instanceof FormArray)) {
          stack.push(rootControl);
        }
    
        while (stack.length > 0) {
          let currentControl = stack.pop();
          (<any>Object).values(currentControl.controls).forEach((control) => {
            // If there are nested forms or formArrays, stack them to visit later
            if (visitChildren &&
                (control instanceof FormGroup || control instanceof FormArray)
               ) {
               stack.push(control);
            } else {
               control.markAsTouched();
            }
          });
        }
      }
    

    This solution works form both FormGroup and also FormArray.

    You can play around with it here: angular-mark-as-touched

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