angular 在触摸之前阻止表单验证

angular prevent form validation until touched

在 Angular 8 个项目中,

我有一个创建和编辑组件。

我只是 duplicated/refactored 创建以进行编辑。

到达编辑模式后,组件订阅了下一个要编辑的对象的行为主题(因为它是行为主题,无论时间范围如何,我的组件都正确地实例化了对象)

在编辑案例中,我没有使用空值来实例化表单,而是直接使用恢复后的值来实例化它。

很好。

现在对于用户来说,实际上他正在编辑那个对象。

问题是首先要创建的对象当然已经满足表单验证条件,因此“提交”按钮突出显示并准备就绪。

我希望触摸的 属性 已经是验证条件,并且在触摸值之前禁用提交按钮。

(不同的是理想的,但感动是一个很好的起点)

现在我的编辑表单一开始是有效的,但我不想这样。

我不想 "hack" 通过设置一个字段的无效标志来实现这一点,因为我不会先发制人地知道用户想要编辑什么,我希望它是任何字段,并且用户只需编辑 1-n 个字段即可使表单有效。

对于Angular^8:

在为控件设置值后将表单标记为原始:

this.form.markAsPristine();

并添加提交按钮的条件,使其在表单未被触及时禁用:

<button type="submit" [disabled]="form.pristine">Save</button>

当您创建控件时,即任何扩展 AbstractControl 的类型,例如 FormGroup、FormControl、ArrayControl…

默认情况下它们将被标记为脏(当然除非您自己实现)。

因此,当您创建这样一个控件并为其分配验证器时,这些验证器将立即被触发。

例如,假设 ErrorOnValidate 是一个总是 return 错误的验证器,下面的 formGroup 将立即保存由验证器 return 编辑的错误。

const formGroup: FormGroup = new FormGroup(
      {
        key: new FormControl('value'),
      },
      {
        validators: [ErrorOnValidate],
      }
    );
console.log(formGroup.valid); /// false

如何防止这种行为?

您需要先创建表单,然后将其设置为原始表单,然后只将验证程序附加到该表单。

const formGroup: FormGroup = new FormGroup(
      {
        key: new FormControl('value'),
      }
    );

formGroup.markAsPristine();

formGroup.setValidators([ErrorOnValidate]);

console.log(formGroup.valid); /// true

这样,当控制器被触摸时,formGroup 将 运行 验证器(因此在此示例中保持验证器的错误)。

但是…… 现在你有了一个带有值和验证器的 FormGroup,在它被触摸之前不会做任何事情。但是,只要您将此 FormGroup 与输入绑定,输入就会触及控件并因此触发验证,这意味着所有这些努力都将失败。

另一种方法是创建一个不带任何验证器的 FormControl,并且仅在视图初始化后才将它们添加到表单中。

ngAfterViewInit(): void {
    this.formGroup.setValidators([ErrorOnValidate])
}