如何在大角度形式的验证中包括/排除FormControls

时间:2018-11-21 16:53:19

标签: angular angular-reactive-forms

如果要从验证中排除特定的FormControl / FormGroup,可以使用反应式形式的AbstractFormControl.disable()。并且您可以使用AbstractFormControl.enable()进行相反的操作。但是有时候,使用大型复杂表格并不容易。

考虑以下形式:

enter image description here

  • 只有选中B,绿色区域才会出现
  • 仅在选中E的情况下才会显示蓝色区域
  • 仅在选中X的情况下才会显示红色区域

上面图片的代码:

   @Component({
      selector: 'my-app',
      template: `<div [formGroup]="form">
          <div style="float: right">
            <label for="ctrlX">X</label>
            <input type="checkbox" formControlName="ctrlX" />
          </div>

          <div class="row">
            <label for="ctrlA">A</label>
            <input type="text" name="ctrlA" formControlName="ctrlA" />
          </div>

          <div class="row">
            <label for="ctrlB">B</label>
            <input type="checkbox" name="ctrlB" formControlName="ctrlB" />
          </div>

          <div *ngIf="form.value.ctrlB === true">
            <div [formGroup]="form.get('detailB')">
              <div class="row">
                <label for="ctrlC">C</label>
                <input type="text" name="ctrlC" formControlName="ctrlC" />
              </div>

              <div class="row" *ngIf="form.value.ctrlX === true">
                <label for="ctrlD">D</label>
                <input type="text" name="ctrlD" formControlName="ctrlD" />
              </div>

              <div class="row">
                <label for="ctrlE">E</label>
                <input type="checkbox" name="ctrlE" formControlName="ctrlE" />
              </div>

              <div *ngIf="form.value.detailB.ctrlE === true">
                <div [formGroup]="form.get('detailB').get('detailE')">
                  <div class="row">
                    <label for="ctrlF">F</label>
                    <input type="text" name="ctrlF" formControlName="ctrlF" />
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="row">
            <label></label>
            <button>Submit</button>
          </div>
        </div>`,
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
      private form = this.formBuilder.group({
        ctrlA: ['', Validators.required],
        ctrlB: [false],
        detailB: this.formBuilder.group({
          ctrlC: ['', Validators.required],
          ctrlD: ['', Validators.required],
          ctrlE: [false],
          detailE: this.formBuilder.group({
            ctrlF: ['', Validators.required]
          })
        }),
        ctrlX: [true],
      });

      constructor(private formBuilder: FormBuilder) {}
    }

现在的事情是,您不想验证用户不可见的内容。但是问题是:如何正确实施?

这是我到目前为止尝试过的。

A :此live example
中展示的控件逐个切换 这可以按预期工作,但是有两个缺点:

  • 代码冗长,不清楚,因此我认为很容易出错
  • 这样,某些控件依赖于多个条件,因此您需要组合条件并合并valueChanges可观察值(例如F不仅依赖于E,而且依赖于B)

B :切换父formGroup而不是live example中展示的特定formControls
问题在于,FormGroup.disable()递归地更改离开并形成的每个后代的状态,与UI相比,状态不一致。

在这些实时示例中,您可以在页面底部的文本区域中看到启用的内容。

1 个答案:

答案 0 :(得分:1)

您可以使用this.formGroup.setValidators(ValidatorFunction)。 Validator函数可以接受formGroup作为参数。您可以检查值并返回错误对象或null。您无需依赖此处的任何可观察对象(删除条件A中的缺点,取决于条件,代码可能很长)。至于B,由于您没有手动启用/禁用控件,因此表单将始终处于一致状态。