【问题标题】:How include/exclude FormControls from validation in large Angular forms如何在大型 Angular 表单的验证中包含/排除 FormControls
【发布时间】:2018-11-22 14:24:24
【问题描述】:

在响应式表单中,当您想从验证中排除特定的 FormControl/FormGroup 时,您可以使用 AbstractFormControl.disable()。你可以使用AbstractFormControl.enable() 来做相反的事情。但有时对于大型复杂表格来说,这并不容易。

考虑以下形式:

  • 只有选中 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 observables(例如,F 不仅依赖于 E,还依赖于 B)李>

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

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

【问题讨论】:

    标签: angular angular-reactive-forms


    【解决方案1】:

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

    【讨论】:

    • 我遇到了与 OP 类似的问题,而您的建议实际上似乎不起作用。如果你可以看一下这个例子:stackblitz.com/edit/angular-9-material-starter-m424mb 这是一个简单的表单组,有两个必需的控件,以及一个始终返回 null 的自定义验证器。根据您的说法,即使两个控件都为空,此设置应该 导致组始终有效,但事实并非如此。看来自定义验证器只是附加的,并不能替代依赖子控件有效性的内部验证。
    猜你喜欢
    • 1970-01-01
    • 2019-10-18
    • 2018-04-19
    • 2012-08-27
    • 2017-10-24
    • 2016-09-06
    • 2017-03-06
    • 2022-01-14
    • 1970-01-01
    相关资源
    最近更新 更多