创建反应式密码确认表单控件?

Creating a reactive password confirmation form control?

我正在尝试创建一个 material 密码确认组件,它可以与 Angular 响应式表单一起使用。这样,可以在注册表单和重置密码表单中使用相同的组件。

I've created a self contained Stackblitz Demo here 工作正常(这是当控件独立使用而不嵌入另一种反应形式时)。密码字段有最小和最大长度验证限制,确认密码字段是必需的。

在满足所有验证约束且密码匹配之前,提交按钮将不会启用。

所以现在我希望能够在 Angular Material Reactive Forms 中使用该组件,并且 according to this article 控件必须实现 ControlValueAccessor 接口和 Validator界面

所以我将这些添加到控件中并实现了 a demo here

表单如下所示:

<mat-card class="PasswordFormTestCard">
  <form class="RegistrationForm" [formGroup]="form" (ngSubmit)="submit()">
    <mat-form-field>
      <input
        matInput
        placeholder="username"
        type="text"
        formControlName="username"
      />
      <mat-hint *ngIf="!username">Example Monica</mat-hint>
      <mat-error>Please enter your username</mat-error>
    </mat-form-field>

    <fs-password-form formControlName="password"></fs-password-form>

    <button mat-button type="submit" [disabled]="!form.valid">Submit</button>
  </form>
</mat-card>

可以看出自定义密码表单控件是这样绑定的:

<fs-password-form formControlName="password"></fs-password-form>

这个“几乎”有效。

只要 confirmPassword 对话框中有任何字符,提交按钮就会启用。

控件上的validate函数应该可以防止这种情况发生。我是这样实现的:

  //=============================================
  // Validator API Methods
  //=============================================
  validate(control: AbstractControl): ValidationErrors | null {
    if (
      this.passwordForm.valid &&
      this.confirmPasswordControl.valid &&
      this.passwordControl.valid
    ) {
      console.log('BOTH THE FORM AND THE CONTROLS ARE VALID');
      return null;
    }

    let errors: any = {};

    errors = this.addControlErrors(errors, 'password');
    errors = this.addControlErrors(errors, 'confirmPassword');

    return errors;
  }

  addControlErrors(allErrors: any, controlName: string) {
    const errors = { ...allErrors };
    const controlErrors = this.passwordForm.controls[controlName].errors;

    if (controlErrors) {
      errors[controlName] = controlErrors;
    }
    return errors;
  }

我认为在返回 null 之前检查表单和控件是否有效,如下所示:

     this.passwordForm.valid &&
      this.confirmPasswordControl.valid &&
      this.passwordControl.valid

将确保自定义 PasswordForm 控件不会在实际有效之前指示它有效,但由于某种原因它会提前返回 null。

有人知道这是为什么吗?

你的时间有问题。当调用验证函数时,FormGroup 的有效性尚未更新。修复非常简单。在验证函数的顶部添加以下行:

this.passwordForm.updateValueAndValidity({
  onlySelf: true,
  emitEvent: false,
});

我认为它不会 side-effects。