基于条件的动态验证

Dynamic validation based on conditions

场景: 我有 4 个表单域。

  1. 描述(可选)
  2. Select 类型(必填)
  3. Phone(仅当 Select 类型设置为 'Phone' 时才需要)
  4. 电子邮件(仅当 Select 类型设置为 'Email' 时才需要)

当我更改 Select 类型字段时,基于 selection,Phone 字段或电子邮件字段将可见。我需要验证这些字段。

问题:

加载表单时,它将只有说明、select 类型下拉菜单和保存按钮。

第 1 步:在不输入任何内容的情况下单击保存按钮,应该会抛出一条警告,提示 Select Type is required 并且 select 类型将为红色。

第2步:Select一个类型,下一个输入变成可见的红色边框。这不应该发生,因为用户没有接触该字段。我该如何解决?

代码:

Stackblitz code

html

<div class="example-container">
    <form [formGroup]="groupForm" (ngSubmit)="onSubmit()">
        <section>
            <section class="input-row">
                <mat-form-field>
                    <input matInput type="test" placeholder="Description" id="description" formControlName="description"/>
        </mat-form-field>
            </section>
            <section class="input-row">
                <mat-form-field>
                    <mat-select id="sourceType" formControlName="sourceType" placeholder="Select Type*">
                        <mat-option value="phone">Phone</mat-option>
                        <mat-option value="email">Email</mat-option>
                    </mat-select>
                </mat-form-field>
            </section>
            <section *ngIf="typeIsPhone" class="input-row">
                <mat-form-field>
                    <input matInput type="number" placeholder="Phone" id="phoneValue" formControlName="phoneValue"/>
        </mat-form-field>
            </section>
            <section *ngIf="typeIsEmail" class="input-row">
                <mat-form-field>
                    <input matInput type="email" placeholder="Email" id="emailValue" formControlName="emailValue"/>
        </mat-form-field>
            </section>
        </section>
        <button mat-raised-button color="primary" type="submit" class="save">
      Save
    </button>
    </form>
</div> 

分量:

export class FormFieldOverviewExample implements OnInit {
  typeIsPhone = false;
  typeIsEmail = false;
  public groupForm: FormGroup = new FormGroup({
    description: new FormControl(""),
    sourceType: new FormControl("", [Validators.required]),
    phoneValue: new FormControl("", [Validators.required]),
    emailValue: new FormControl("", [Validators.required])
  });

  constructor() {}

  ngOnInit(): void {
    this.groupForm
      .get("sourceType")
      .valueChanges.subscribe(this.setSourceType.bind(this));
  }

  setSourceType(SourceType: string) {
    this.typeIsPhone = SourceType === "phone";
    this.typeIsEmail = SourceType === "email";
  }

  onSubmit() {
    const sourceTypeFormControl = this.groupForm.get("sourceType");
    const phoneEnteredFormControl = this.groupForm.get("phoneValue");
    const emailEnteredFormControl = this.groupForm.get("emailValue");

    if (sourceTypeFormControl.errors.required) {
      alert("Source Type is required!");
      return;
    } else {
      if (phoneEnteredFormControl.errors.required) {
        alert("Phone is required!");
        return;
      }
      if (emailEnteredFormControl.errors.required) {
        alert("email is required!");
        return;
      }
    }
  }
}

问题源于提交 属性、隐含类型=提交的按钮以及默认 ErrorStateMatcher 处理此问题的方式 case

也许使用

type="button" (click)="onSubmit()"

好像禁用了 FormControl 没有错误我建议使用禁用和启用的另一种方法,您可以在 this stackblitz

中看到
ngOnInit(): void {
    const control=this.groupForm.get("sourceType")
    if (control)
       control.valueChanges.pipe( //Use startWith to execute at first
             startWith(control.value)
       ).subscribe(res=>this.setSourceType(res)); //<--see how pass the value
  }

  setSourceType(SourceType: string) {
    this.typeIsPhone = SourceType === "phone";
    this.typeIsEmail = SourceType === "email";
    const phoneControl=this.groupForm.get('phoneValue')
    const emailControl=this.groupForm.get('emailValue')
    if (phoneControl) 
      phoneControl[SourceType==='phone'?'enable':'disable']() //(*)
    if (emailControl)
      emailControl[SourceType==='email'?'enable':'disable']()
  }
  //(*) is a abreviated way to say 
  //             if (SourceType=='phone')
  //                phoneControl.enable()
  //             else
  //                phoneControl.disable()

注意:

  //You can not use 
  if (phoneEnteredFormControl.errors.required) //WRONG
  //use 
  if (phoneEnteredFormControl.errors && phoneEnteredFormControl.errors.required) //OK