Angular 5 FormGroup重置不会重置验证器

时间:2018-01-11 21:46:44

标签: angular angular-reactive-forms

我的页面上有一个表单,当我致电FormGroup.reset()时,它会将表单类设置为ng-pristine ng-untouched,但FormControl.hasError(...)仍会返回真值。我在这里做错了什么?

模板

<form [formGroup]="myForm" (ngSubmit)="submitForm(myForm)">
  <mat-form-field>
    <input matInput formControlName="email" />
    <mat-error *ngIf="email.hasError('required')">
      Email is a required feild
    </mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput type="password" formControlName="password" />
    <mat-error *ngIf="password.hasError('required')">
      Password is a required feild
    </mat-error>
  </mat-form-field>
  <button type="submit">Login</button>
</form>

组件

export class MyComponent {
  private myForm: FormGroup;
  private email: FormControl = new FormContorl('', Validators.required);
  private password: FormControl = new FormControl('', Validators.required);

  constructor(
    private formBuilder: FormBuilder
  ) {
    this.myForm = formBuilder.group({
      email: this.email,
      password: this.password
    });
  }

  private submitForm(formData: any): void {
    this.myForm.reset();
  }
}

Plunker

http://embed.plnkr.co/Hlivn4/

15 个答案:

答案 0 :(得分:73)

它(FormGroup)行为正确。您的表单需要用户名和密码,因此当您重置表单时,它应该是无效的(即没有用户名/密码的表单无效)。

如果我理解正确,那么您的问题就是为什么在您第一次加载页面时(表单无效时)没有出现红色错误,但单击按钮时弹出错误。当您使用Material时,此问题尤为突出。

AFAIK,<mat-error>检查FormGroupDirective的有效性,而非FormGroup的有效性,重置FormGroup不会重置FormGroupDirective。这有点不方便,但要清除<mat-error>,您还需要重置FormGroupDirective

为此,在模板中定义一个变量:

<form [formGroup]="myForm" #formDirective="ngForm" 
  (ngSubmit)="submitForm(myForm, formDirective)">

在您的组件类中,请致电formDirective.resetForm()

private submitForm(formData: any, formDirective: FormGroupDirective): void {
    formDirective.resetForm();
    this.myForm.reset();
}

GitHub问题:https://github.com/angular/material2/issues/4190

答案 1 :(得分:8)

resetForm() {

    this.loginForm.reset();

    for( let i in this.loginForm.controls ) {

        this.loginForm.controls[i].setErrors(null);
    }
}

答案 2 :(得分:6)

除了Harry Ninh的解决方案之外,如果您想在组件中访问formDirective而不需要选择表单按钮,则:

模板:

<form 
  ...
  #formDirective="ngForm" 
>

组件:

import { ViewChild, ... } from '@angular/core';
import { NgForm, ... } from '@angular/forms';

export class MyComponent {
 ...
 @ViewChild('formDirective') private formDirective: NgForm;

  constructor(... )

  private someFunction(): void { 
    ...
    formDirective.resetForm();
  }
}

答案 3 :(得分:2)

2021 年更新 - ANGULAR 11.2

直接在 HTML 函数中使用 [formGroup]="form#formDirective="ngForm" 并不是一个好习惯。或者您可能更喜欢使用 @ViewChild,并直接从您的 .ts 中执行此操作。其实问题不在于Angular,而在于Material。

如果您查看他们的 GitHub,您会看到:

/** Provider that defines how form controls behave with regards to displaying error messages. */
@Injectable({providedIn: 'root'})
export class ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    return !!(control && control.invalid && (control.touched || (form && form.submitted)));
  }
}

表单将保持其 submitted 状态。所以你只需要删除函数的最后一部分。 这是我的解决方案(测试和工作)。我有一个材料模块,我已经实现了这个:

export class ShowOnInvalidTouchedErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl): boolean {
    return !!(control && control.invalid && control.touched);
  }
}

@NgModule({
  providers: [
    {
      provide: ErrorStateMatcher, useClass: ShowOnInvalidTouchedErrorStateMatcher
    }
  ],
  exports: [
    MatSnackBarModule,
    MatTabsModule,
    ...
  ]
});

如果您只想在一种表单上使用此 ErrorStateMatcher,这是可能的。请参阅this Material example。这是同一个原理。

答案 4 :(得分:1)

添加属性-

@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;

并使用它代替this.myForm.reset();

this.formGroupDirective.resetForm();

这将重置错误显示并完成form.reset()的工作。但是表单以及字段仍将显示ng-invalid

查看此答案以获取更多详细信息-https://stackoverflow.com/a/56518781/9262627

答案 5 :(得分:0)

我也遇到同样的问题。我的问题是我正在使用mat-form-fieldformGroup。重置表单submitted后,标志未重置。

因此,对我有用的解决方案是将ngForm的指令与formGroup一起放入并传递onSubmit(form)。添加 @ViewChild('form') form; 在组件中,然后我用 this.form.resetForm();

答案 6 :(得分:0)

我发现在调用resetForm()和reset()之后,提交的未重置并且保持为true,从而导致显示错误消息。这个解决方案对我有用。我在寻找在输入标签上调用select()和focus()的解决方案时找到了它,该标签也无法按预期工作。只需将您的行包装在setTimeout()中。有点hack,但是可以解决问题。

<form [formGroup]="myFormGroup" #myForm="ngForm">
    …
    <button mat-raised-button (click)="submitForm()">
</form>
submitForm() { 
    …
    setTimeout(() => {
        this.myForm.resetForm();
        this.myFormGroup.reset();
    }, 0);
}

答案 7 :(得分:0)

当尝试重置表单组中的特定表单控制器时,以下解决方案对我有用-

 this.myForm.get('formCtrlName').reset();
 this.myForm.get('formCtrlName').setValidators([Validators.required, Validators.maxLength(45), Validators.minLength(4), Validators.pattern(environment.USER_NAME_REGEX)]);
 this.myForm.get('formCtrlName').updateValueAndValidity();

答案 8 :(得分:0)

没有什么能满足我的要求(Angular 7.2,Angular Material 7.3.7)。

尝试通过Submit方法在视图上传递事件:

<form [formGroup]="group" (ngSubmit)="onSubmit($event)">
    <!-- your form here -->
</form>

然后使用它来重置currentTarget和之后的表单:

public onSubmit(event): void {
  // your code here
  event.currentTarget.reset()
  this.group.reset()
}

答案 9 :(得分:0)

简单的解决方法:将按钮与type="reset"和功能submitForm()一起使用

<form [formGroup]="MyForm" (ngSubmit)="submitForm()">
  <input formControlName="Name">
  <mat-error>  
    <span *ngIf="!tunersForm.get('Name').value && tunersForm.get('Name').touched"></span>  
  </mat-error>
  <button type="reset" [disabled]="!MyForm.valid" (click)="submitForm()">Save</button>
</form>

答案 10 :(得分:0)

我对重置form指令没有运气。但是您也可以将输入状态更改为“待处理”。

this.myForm.get("email").reset();
this.myForm.get("password").reset();

答案 11 :(得分:0)

对于可能对此有帮助的任何人,我正在运行Angular 9.1.9,并且我不想仅重置表单的整体有效性来重置表单/控件,所以我只运行了

this.registerForm.setErrors(null);

...其中registerForm: FormGroup会重置表格错误,导致:

this.registerForm.valid

...返回true

对于控件也可以这样做:

this.registerForm.get('email').setErrors(null)

触摸表单后,无论如何都会重新评估这些错误,因此,如果这还不够好,则当您要开始显示/隐藏错误UI时,可能需要使用布尔值标记来进一步精确定位。

在我的情况下,我不需要触摸指令。

答案 12 :(得分:0)

 resetForm() {
    this.myFormGroup.reset();
    this.myFormGroup.controls.food.setErrors(null);
    this.myFormGroup.updateValueAndValidity();
  } 

答案 13 :(得分:0)

form.reset()在像Angular Material这样的自定义窗体控件上将不起作用,这就是该功能无法按预期工作的原因。

我的解决方法是这样的

    this.form.reset();
    for (let control in this.form.controls) {
      this.form.controls[control].setErrors(null);
    }

this.form.reset()的问题是它将重置您的formcontrol值,但不会重置错误,因此您需要通过此代码行分别重置它们

for (let control in this.form.controls) {
      this.form.controls[control].setErrors(null);
    }

使用此方法,您无需使用FormGroupDirective,这对我来说是一种更干净的解决方案。

Github问题:https://github.com/angular/angular/issues/15741

答案 14 :(得分:-2)

将提交功能从表单移动到按钮,并向按钮添加类型:

<form [formGroup]="createForm">
  <button (click)="submitForm()" type="submit">Submit</button>
  <button (click)="createForm.reset()" type="reset">Reset</button>
</form>