Angular 5 FormGroup 重置不会重置验证器
Angular 5 FormGroup reset doesn't reset validators
我的页面上有一个表单,当我调用 FormGroup.reset()
时,它将表单 class 设置为 ng-pristine ng-untouched
但 FormControl.hasError(...)
仍然 returns 真实。我在这里做错了什么?
模板
<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();
}
}
笨蛋
它 (FormGroup
) 行为正确。您的表单需要用户名和密码,因此当您重置表单时它应该是无效的(即没有 username/password 的表单无效)。
如果我没理解错的话,你的问题是为什么在你第一次加载页面时红色错误不存在(表单也无效)但是当你点击按钮时弹出。当您使用 Material.
时,此问题尤为突出
AFAIK,<mat-error>
检查 FormGroupDirective
的有效性,而不是 FormGroup
,并且重置 FormGroup
不会重置 FormGroupDirective
。这有点不方便,但要清除 <mat-error>
,您还需要重置 FormGroupDirective
。
为此,在您的模板中定义一个变量:
<form [formGroup]="myForm" #formDirective="ngForm"
(ngSubmit)="submitForm(myForm, formDirective)">
然后在您的组件 class 中调用 formDirective.resetForm()
:
private submitForm(formData: any, formDirective: FormGroupDirective): void {
formDirective.resetForm();
this.myForm.reset();
}
阅读评论后这是正确的方法
// you can put this method in a module and reuse it as needed
resetForm(form: FormGroup) {
form.reset();
Object.keys(form.controls).forEach(key => {
form.get(key).setErrors(null) ;
});
}
不需要调用 form.clearValidators()
除了 Harry Ninh 的解决方案之外,如果您想访问组件中的 formDirective 而无需 select 表单按钮,则:
模板:
<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();
}
}
我也遇到了同样的问题。我的问题是我使用的是 mat-form-field
和 formGroup
。重置表单后 submitted
标志未重置。
所以,对我有用的解决方案是,将 ngForm
指令与 formGroup
一起放置并传递 onSubmit(form)
。添加
@ViewChild('form') form;
在组件中,然后我使用
this.form.resetForm();
我发现在调用resetForm()和reset()后,submitted并没有被reset,仍然是true,导致显示错误信息。这个解决方案对我有用。我在寻找在输入标签上调用 select() 和 focus() 的解决方案时发现了它,但它也没有按预期工作。只需将您的行包装在 setTimeout() 中。我认为 setTimeout 强制 Angular 检测变化,但我可能是错的。这有点骇人听闻,但确实有效。
<form [formGroup]="myFormGroup" #myForm="ngForm">
…
<button mat-raised-button (click)="submitForm()">
</form>
submitForm() {
…
setTimeout(() => {
this.myForm.resetForm();
this.myFormGroup.reset();
}, 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();
以上对我没有任何帮助(Angular 7.2,Angular Material 7.3.7)。
尝试使用提交方法传递视图中的事件:
<form [formGroup]="group" (ngSubmit)="onSubmit($event)">
<!-- your form here -->
</form>
然后用它来重置 currentTarget
和你的表单:
public onSubmit(event): void {
// your code here
event.currentTarget.reset()
this.group.reset()
}
简单修复:将按钮与 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>
我没能重置表单指令。但是您也可以将输入状态更改为待处理。
this.myForm.get("email").reset();
this.myForm.get("password").reset();
对于这可能有帮助的任何人,我是 运行 Angular 9.1.9 我不想重置 form/controls 只是表格的整体有效性所以我只是 运行:
this.registerForm.setErrors(null);
...其中 registerForm: FormGroup
并重置表单错误,导致:
this.registerForm.valid
...返回 true
。
控件也可以这样做:
this.registerForm.get('email').setErrors(null)
一旦表单被触摸,这些错误就会被重新评估,所以如果这还不够好,您可能需要一个布尔标志来进一步确定您想要开始的时间 showing/hiding 错误 UI.
我不需要触及指令。
resetForm() {
this.myFormGroup.reset();
this.myFormGroup.controls.food.setErrors(null);
this.myFormGroup.updateValueAndValidity();
}
添加 属性 -
@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;
并使用它代替 this.myForm.reset();
this.formGroupDirective.resetForm();
这将重置错误显示并完成 form.reset() 的工作。但是表单和字段仍然会显示 ng-invalid
class
查看此答案了解更多详情 -
form.reset()
无法在像 Angular Material 这样的自定义表单控件上工作,这就是该功能未按预期工作的原因。
我的解决方法是这样的
this.form.reset();
for (let control in this.form.controls) {
this.form.controls[control].setErrors(null);
}
this.form.reset()
问题在于它会重置您的表单控件值而不是错误,因此您需要通过这行代码单独重置它们
for (let control in this.form.controls) {
this.form.controls[control].setErrors(null);
}
有了这个你就不需要使用 FormGroupDirective
这对我来说是一个更干净的解决方案。
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
状态。所以你只需要删除函数的最后一部分。
这是我的解决方案(已测试并有效)。我有一个 Material 模块,我已经实现了这个:
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。这也是一样的道理。
我的页面上有一个表单,当我调用 FormGroup.reset()
时,它将表单 class 设置为 ng-pristine ng-untouched
但 FormControl.hasError(...)
仍然 returns 真实。我在这里做错了什么?
模板
<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();
}
}
笨蛋
它 (FormGroup
) 行为正确。您的表单需要用户名和密码,因此当您重置表单时它应该是无效的(即没有 username/password 的表单无效)。
如果我没理解错的话,你的问题是为什么在你第一次加载页面时红色错误不存在(表单也无效)但是当你点击按钮时弹出。当您使用 Material.
时,此问题尤为突出AFAIK,<mat-error>
检查 FormGroupDirective
的有效性,而不是 FormGroup
,并且重置 FormGroup
不会重置 FormGroupDirective
。这有点不方便,但要清除 <mat-error>
,您还需要重置 FormGroupDirective
。
为此,在您的模板中定义一个变量:
<form [formGroup]="myForm" #formDirective="ngForm"
(ngSubmit)="submitForm(myForm, formDirective)">
然后在您的组件 class 中调用 formDirective.resetForm()
:
private submitForm(formData: any, formDirective: FormGroupDirective): void {
formDirective.resetForm();
this.myForm.reset();
}
阅读评论后这是正确的方法
// you can put this method in a module and reuse it as needed
resetForm(form: FormGroup) {
form.reset();
Object.keys(form.controls).forEach(key => {
form.get(key).setErrors(null) ;
});
}
不需要调用 form.clearValidators()
除了 Harry Ninh 的解决方案之外,如果您想访问组件中的 formDirective 而无需 select 表单按钮,则:
模板:
<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();
}
}
我也遇到了同样的问题。我的问题是我使用的是 mat-form-field
和 formGroup
。重置表单后 submitted
标志未重置。
所以,对我有用的解决方案是,将 ngForm
指令与 formGroup
一起放置并传递 onSubmit(form)
。添加
@ViewChild('form') form;
在组件中,然后我使用
this.form.resetForm();
我发现在调用resetForm()和reset()后,submitted并没有被reset,仍然是true,导致显示错误信息。这个解决方案对我有用。我在寻找在输入标签上调用 select() 和 focus() 的解决方案时发现了它,但它也没有按预期工作。只需将您的行包装在 setTimeout() 中。我认为 setTimeout 强制 Angular 检测变化,但我可能是错的。这有点骇人听闻,但确实有效。
<form [formGroup]="myFormGroup" #myForm="ngForm">
…
<button mat-raised-button (click)="submitForm()">
</form>
submitForm() {
…
setTimeout(() => {
this.myForm.resetForm();
this.myFormGroup.reset();
}, 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();
以上对我没有任何帮助(Angular 7.2,Angular Material 7.3.7)。
尝试使用提交方法传递视图中的事件:
<form [formGroup]="group" (ngSubmit)="onSubmit($event)">
<!-- your form here -->
</form>
然后用它来重置 currentTarget
和你的表单:
public onSubmit(event): void {
// your code here
event.currentTarget.reset()
this.group.reset()
}
简单修复:将按钮与 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>
我没能重置表单指令。但是您也可以将输入状态更改为待处理。
this.myForm.get("email").reset();
this.myForm.get("password").reset();
对于这可能有帮助的任何人,我是 运行 Angular 9.1.9 我不想重置 form/controls 只是表格的整体有效性所以我只是 运行:
this.registerForm.setErrors(null);
...其中 registerForm: FormGroup
并重置表单错误,导致:
this.registerForm.valid
...返回 true
。
控件也可以这样做:
this.registerForm.get('email').setErrors(null)
一旦表单被触摸,这些错误就会被重新评估,所以如果这还不够好,您可能需要一个布尔标志来进一步确定您想要开始的时间 showing/hiding 错误 UI.
我不需要触及指令。
resetForm() {
this.myFormGroup.reset();
this.myFormGroup.controls.food.setErrors(null);
this.myFormGroup.updateValueAndValidity();
}
添加 属性 -
@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;
并使用它代替 this.myForm.reset();
this.formGroupDirective.resetForm();
这将重置错误显示并完成 form.reset() 的工作。但是表单和字段仍然会显示 ng-invalid
class
查看此答案了解更多详情 -
form.reset()
无法在像 Angular Material 这样的自定义表单控件上工作,这就是该功能未按预期工作的原因。
我的解决方法是这样的
this.form.reset();
for (let control in this.form.controls) {
this.form.controls[control].setErrors(null);
}
this.form.reset()
问题在于它会重置您的表单控件值而不是错误,因此您需要通过这行代码单独重置它们
for (let control in this.form.controls) {
this.form.controls[control].setErrors(null);
}
有了这个你就不需要使用 FormGroupDirective
这对我来说是一个更干净的解决方案。
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
状态。所以你只需要删除函数的最后一部分。
这是我的解决方案(已测试并有效)。我有一个 Material 模块,我已经实现了这个:
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。这也是一样的道理。