Reactive Forms - mark fields as touched

后端 未结 19 1473
旧时难觅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:48

    I ran into the same problem, but I do not want to "pollute" my components with code that handles this. Especially since I need this in many forms and I do not want to repeat the code on various occasions.

    Thus I created a directive (using the answers posted so far). The directive decorates NgForm's onSubmit-Method: If the form is invalid it marks all fields as touched and aborts submission. Otherwise the usual onSubmit-Method executes normally.

    import {Directive, Host} from '@angular/core';
    import {NgForm} from '@angular/forms';
    
    @Directive({
        selector: '[appValidateOnSubmit]'
    })
    export class ValidateOnSubmitDirective {
    
        constructor(@Host() form: NgForm) {
            const oldSubmit = form.onSubmit;
    
            form.onSubmit = function (): boolean {
                if (form.invalid) {
                    const controls = form.controls;
                    Object.keys(controls).forEach(controlName => controls[controlName].markAsTouched());
                    return false;
                }
                return oldSubmit.apply(form, arguments);
            };
        }
    }
    

    Usage:

    <form (ngSubmit)="submit()" appValidateOnSubmit>
        <!-- ... form controls ... -->
    </form>
    
    0 讨论(0)
  • 2020-12-04 23:49

    From Angular 8/9 you can simply use

    this.form.markAllAsTouched();
    

    To mark a control and it's descendant controls as touched.

    AbstractControl doc

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

    as per @masterwork

    typescript code for the angular version 8

    private markFormGroupTouched(formGroup: FormGroup) {
        (Object as any).values(formGroup.controls).forEach(control => {
          control.markAsTouched();
          if (control.controls) {
            this.markFormGroupTouched(control);
          }
        });   }
    
    0 讨论(0)
  • 2020-12-04 23:49

    See this gem. So far the most elegant solution I've seen.

    Full code

    import { Injectable } from '@angular/core';
    import { FormGroup } from '@angular/forms';
    
    const TOUCHED = 'markAsTouched';
    const UNTOUCHED = 'markAsUntouched';
    const DIRTY = 'markAsDirty';
    const PENDING = 'markAsPending';
    const PRISTINE = 'markAsPristine';
    
    const FORM_CONTROL_STATES: Array<string> = [TOUCHED, UNTOUCHED, DIRTY, PENDING, PRISTINE];
    
    @Injectable({
      providedIn: 'root'
    })
    export class FormStateService {
    
      markAs (form: FormGroup, state: string): FormGroup {
        if (FORM_CONTROL_STATES.indexOf(state) === -1) {
          return form;
        }
    
        const controls: Array<string> = Object.keys(form.controls);
    
        for (const control of controls) {
          form.controls[control][state]();
        }
    
        return form;
      }
    
      markAsTouched (form: FormGroup): FormGroup {
        return this.markAs(form, TOUCHED);
      }
    
      markAsUntouched (form: FormGroup): FormGroup {
        return this.markAs(form, UNTOUCHED);
      }
    
      markAsDirty (form: FormGroup): FormGroup {
        return this.markAs(form, DIRTY);
      }
    
      markAsPending (form: FormGroup): FormGroup {
        return this.markAs(form, PENDING);
      }
    
      markAsPristine (form: FormGroup): FormGroup {
        return this.markAs(form, PRISTINE);
      }
    }
    
    0 讨论(0)
  • 2020-12-04 23:50

    The following function recurses through controls in a form group and gently touches them. Because the controls field is an object, the code call Object.values() on the form group's control field.

      /**
       * Marks all controls in a form group as touched
       * @param formGroup - The form group to touch
       */
      private markFormGroupTouched(formGroup: FormGroup) {
        (<any>Object).values(formGroup.controls).forEach(control => {
          control.markAsTouched();
    
          if (control.controls) {
            this.markFormGroupTouched(control);
          }
        });
      }
    
    0 讨论(0)
  • 2020-12-04 23:50

    From Angular v8, you have this built-in with the help of the markAllAsTouched method.

    As an example, you could use it like

    form.markAllAsTouched();
    

    See the official doc : https://angular.io/api/forms/AbstractControl#markallastouched

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