提交后在 Angular 的响应式表单上显示客户端错误和服务器错误

问题描述

使用 Angular 12 我有一个带有客户端和服务器验证的简单示例表单。

  1. 我只想在第一次提交表单后显示客户端验证错误

  2. 我会在客户端验证成功后显示服务器验证错误

    服务器验证错误添加为表单字段错误中的“不正确”字段。

  3. 我正在使用响应式表单。

表单按预期工作,但我不确定我的实施是否是最佳选择。

组件的 HTML

<form [formGroup]="form">
  <label for="email">Email</label>
  <input id="email" type="text" formControlName="email">
  
  <span class="error" *ngIf="form.get('email')?.invalid && form.get('email')?.touched">
    {{form.get('email')?.errors?.incorrect}}
    <ng-container *ngIf="form.get('email')?.errors?.required">Email required</ng-container>
    <ng-container *ngIf="form.get('email')?.errors?.email">Invalid email</ng-container>
  </span>

  <button type="submit" (click)="send()" [disabled]="submitted">Send</button>
</form>

组件的打字稿

export class Component implements OnInit {

  form: FormGroup;
  submitted: boolean;

  constructor(private service: Service) { 

    this.form = this.formBuilder.group({ 
      email: ['',[Validators.required,Validators.email]],});

    this.submitted = false;

  }

  send() {

    this.submitted = true;
    this.form.markAllAsTouched();

    if (this.form.valid) {

      this.service.send({email: this.form.value.email}).subscribe(
        
        (next: Payload<Response>) => { 
          console.log("SUCCESS");
        },(error) => {
          if (error.status === 400)
            new FormGroupErrorBuilder(this.form).setErrors(error.errors);
          this.submitted = false;
        }

      );

    } else {
      this.submitted = false;
    }

  }    

}

FormGroupErrorBuilder

This is how I am adding server errors to Angular's FormGroup:

export class FormGroupErrorBuilder {

  formGroup: FormGroup;

  constructor(formGroup: FormGroup) {
    this.formGroup = formGroup;
  }

  setErrors(errors: Error[]) {

    for (let error of errors) {

      var control = this.formGroup.get(error.name);

      if (control)
        control.setErrors({ incorrect: error.message });
        
    }

  } 

} 

问题

  1. 在首次提交时使用 this.form.markAllAsTouched(); 对所有表单字段进行验证是否可以接受?

  2. 使用条件 *ngIf="form.get('email')?.invalid && form.get('email')?.touched"显示表单域错误的好选择吗?

欢迎任何改进代码的建议......

注意:

我使用 submitted 变量来控制提交按钮是否被禁用并更改其 CSS 样式。

解决方法

查看异步自定义验证器 in the docs

如果您使用选项 {updateOption:'submit'} 创建您的 formGroup,我认为您可以通过其他方式实现

有些像:例如(我把validator放在FormGroup里,你可以放在自己的控件Email里)——那你应该改一下“validateEmail”函数。

this.form = this.formBuilder.group({ 
  email: ['',[Validators.required,Validators.email]],},{updateOption:'submit',asyncValidator:this.validateEmail()});


  validateEmail(): AsyncValidatorFn {
    return (group: FormGroup): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
      return 
         this.service.send({email:group.value.email}).map(res=>{
            if (res.success)
                return null
            return { repeat: "name yet register" }
         })
      )))

    };
  }

注意:当您订阅该服务时,我在您的代码中没有看到清楚。您“捕获”了错误,通常 API 会返回类似 {success:true}{error:'the email is yet!'} 的内容,但如果调用中没有错误,则不要返回状态 400 - 您的 API 可以响应类似以上,但您收到了成功的响应,而不是错误。