【问题标题】:angular 7 material stepper reactive form reset not working角度7材料步进反应形式重置不起作用
【发布时间】:2019-12-18 02:54:37
【问题描述】:

我在 Angular 7 中使用 Angular Material。我有许多响应式表单,每个表单都在自己的控件中,并且每个表单都会更新正在编辑的主要对象的不同属性集合。这些控件都托管在 Angular Material Stepper 控件的不同步骤中。

每个控件都有一个名为“Add New”的按钮,它允许用户向集合中添加一个新对象,以及一个“Edit”按钮来编辑集合中的任何现有项目。每当单击“添加新”按钮时,我都会使用默认值(大部分为空)创建一个新项目,并将其绑定到控件中的反应式表单。

表单始终允许用户单击“添加到集合”按钮(即,该按钮永远不会被禁用),并且验证错误(如果有)会在那时向用户显示。 (如果存在验证错误,则该项目不会添加到集合中。)

一切正常,直到我进入 Stepper 控件的另一个步骤,然后返回我正在处理的步骤。发生这种情况时,我单击“添加新”按钮,我会立即看到所有必需的验证错误,即使用户没有单击“添加到集合”按钮也是如此。当我查看控件的值时,我看不出应该显示验证错误的任何原因,但它们是(空输入周围的红色突出显示)。

这是每当用户单击“添加新”时我正在运行的代码:

public resetForm(formGroup: FormGroup) {
if (!formGroup)
  return;

  formGroup.reset();
  formGroup.clearValidators();
  // see https://stackoverflow.com/questions/48216330/angular-5-formgroup-reset-doesnt-reset-validators
  Object.keys(formGroup.controls).forEach(key => {
    if (ignoreControls.indexOf(key) == -1) {
      formGroup.get(key).setErrors(null);
      formGroup.get(key).markAsPristine();
      formGroup.get(key).markAsUntouched();
      formGroup.get(key).clearValidators();
      formGroup.get(key).updateValueAndValidity();
    }
  }); 

当我查看单个控件时,在 html 中,我看到了我希望看到的所有内容:

<input _ngcontent-wyd-c14="" class="mat-input-element mat-form-field-autofill-control cdk-text-field-autofill-monitored ng-untouched ng-pristine ng-invalid" formcontrolname="title" matinput="" placeholder="e.g. Customer Service Representative" required="" type="text" ng-reflect-required="" ng-reflect-name="title" ng-reflect-placeholder="e.g. Customer Service Represen" ng-reflect-type="text" id="mat-input-24" aria-invalid="true" aria-required="true">

请注意,该类包含 ng-untouched 和 ng-pristine(以及 ng-invalid)。如果一个字段是原始的并且未被触及,它不应该显示验证错误。

我怀疑在 Stepper 控件上更改为不同的步骤会导致某种形式的表单提交或提交尝试,这就是显示所有错误的原因(form.submitted == true 或类似的东西)。但我不知道如何重置任何东西以将表单视为全新的。

谁能帮忙?

(注意:我看到许多 SO 文章建议我需要在 form 指令上调用 resetForm,而不是 formGroup(参见,例如,Angular 5 FormGroup reset doesn't reset validators)。 但是,当我将 #formDirective="ngForm" 添加到我的表单标签并添加到我的打字稿时:

@ViewChild('formDirective') private formDirective: NgForm;

然后我调用 this.formDirective.resetForm(),没有区别 - 验证错误仍会立即显示。

更新:这是一个基本上显示问题的堆栈闪电战。在第一步中单击“保存并继续”,然后在第二步中单击“添加新”。表单显示没有验证错误。现在单击步进器的“Intro”步骤,然后单击返回“Experiences”步骤,当您返回该步骤时,您会看到所有验证都出现了。这是我实际生产项目中的问题——用户应该能够在不触发验证的情况下从一个步骤导航到另一个步骤。在体验组件中,您可以看到每次调用 intiForm 方法时都会尝试重置表单,但您仍然会看到错误。为什么?链接:https://stackblitz.com/edit/angular-w4iunu

【问题讨论】:

  • 你认为你可以在 stackblitz.com(最低版本)中复制它吗?

标签: angular


【解决方案1】:

我怀疑是在步进器上更改为不同的步骤 控制导致某种形式的表单提交或提交尝试,并且 这就是为什么所有错误都显示的原因(form.submitted == true 或其他东西 像那样)。

你就在这里。单击“添加新”按钮会导致提交表单,因为任何button in HTML by default 的类型为submit。点击Add New 按钮后,您的表单将获得submitted 标志。

解决方案应该很简单:

 <button mat-raised-button color="primary" (click)="addNew()" type="button"...>Add New</button>
                                                               ^^^^^^^^^
                                                              add this

Forked Stackblitz

这里的另一个问题是 Stepper 在计算控件的错误状态时考虑了步骤的interacted 属性。一旦你从一个步骤移动到另一个步骤,它就会变成true

您可以通过在selectionChange 上重置此属性来解决此问题:

app.component.html

<mat-horizontal-stepper #diaryStepper ... (selectionChange)="stepIndexChanged(diaryStepper)"

app.component.ts

stepIndexChanged(stepper) {
  stepper.steps.toArray().forEach(step => step.interacted = false)
}

Updated Stackblitz

【讨论】:

  • 我做了这个更改,当我第一次点击“添加新”时,它确实阻止了验证的发生。我进入体验步骤。但是如果你点击“Add New”,然后点击stepper的“Intro”步骤,然后点击回到“Experiences”步骤,你会看到当你返回到该步骤时所有的验证都出现了。这是我实际生产项目中的问题 - 用户应该能够在不触发验证的情况下从一个步骤导航到另一个步骤。
  • @JRS 我同意你的看法。请查看更新后的答案。
  • 做到了!我的生产应用程序现在按预期工作。太感谢了!出于好奇,您是从哪里找到这些信息的?
猜你喜欢
  • 2022-11-25
  • 2020-04-26
  • 2020-05-19
  • 2019-07-29
  • 2021-11-04
  • 2021-11-25
  • 2018-07-20
  • 2021-03-04
  • 1970-01-01
相关资源
最近更新 更多