首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在值更改时处理禁用/启用窗体

在值更改时处理禁用/启用窗体
EN

Stack Overflow用户
提问于 2020-08-04 10:15:41
回答 2查看 715关注 0票数 0

我有一个表单组,其中不同的窗体控件相互链接。每个窗体控件只有在已填充前一个窗体控件时才启用。另外,如果清除了一个窗体控件,那么所有下一个窗体控件都应该被清除和禁用。

我做了一个小小的例子来解释用例。在我的示例中,我处理四个窗体控件,而在实际用例中,我有更多的窗体控件。我不认为这个实现是优雅的,也不是很好的扩展。你有更好的实现吗?

stackblitz中的工作实例

代码语言:javascript
复制
export class AppComponent implements OnInit {
  public myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  public ngOnInit(): void {
    this.myForm = this.getMyForm();
    this.handleFormValueChanges(this.myForm);
  }

  private getMyForm(): FormGroup {
    return this.fb.group({
      company: null,
      country: [{
        value: null,
        disabled: true
      }],
      user: [{
        value: null,
        disabled: true
      }],
      adress: [{
        value: null,
        disabled: true
      }]
    });
  }

  /**
   * Handle myForm value changes (didn't handle unsubscriptions because it is just an example)
   * TODO: Find another implementation
   */
  private handleFormValueChanges(form: FormGroup): void {
    form.get("company").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("country").reset();
        form.get("country").disable();

        form.get("user").reset();
        form.get("user").disable();

        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("country").enable();
      }
    });

    form.get("country").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("user").reset();
        form.get("user").disable();

        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("user").enable();
      }
    });

    form.get("user").valueChanges.subscribe((value: string) => {
      if (!value) {
        form.get("adress").reset();
        form.get("adress").disable();
      } else {
        form.get("adress").enable();
      }
    });
  }
}

编辑:我最终实现了Fabio Carpinato的解决方案的一些变化

这里是stackblitz

代码语言:javascript
复制
import { Component, OnInit, ChangeDetectionStrategy } from "@angular/core";
import { FormGroup, FormBuilder } from "@angular/forms";
import { merge } from "rxjs";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent implements OnInit {
  public myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  public ngOnInit(): void {
    this.myForm = this.getMyForm();
    this.handleFormValueChanges(this.myForm);
  }

  private getMyForm(): FormGroup {
    return this.fb.group({
      company: null,
      country: [{ value: null, disabled: true }],
      user: [{ value: null, disabled: true }],
      adress: [{ value: null, disabled: true }]
      /*
      ... other formcontrols
      */
    });
  }

  /**
   * Handle myForm value changes (didn't handle unsubscriptions nor debounceTime because it is just an example)
   */
  private handleFormValueChanges(form: FormGroup): void {
    const controlDisabledDependencies: { [controlKey: string]: string } = {
      company: null,
      country: "company",
      user: "country",
      adress: "user"
    };

    merge(
      ...Object.keys(controlDisabledDependencies).map(
        (controlKey: string) => form.get(controlKey).valueChanges
      )
    ).subscribe(() => {
      Object.keys(controlDisabledDependencies).forEach((controlKey: string) => {
        if (
          form.get(controlDisabledDependencies[controlKey]) &&
          !form.get(controlDisabledDependencies[controlKey]).value
        ) {
          form.get(controlKey).disable({ emitEvent: false, onlySelf: true });
          form
            .get(controlKey)
            .reset(null, { emitEvent: false, onlySelf: true });
        } else {
          form.get(controlKey).enable({ emitEvent: false, onlySelf: true });
        }
      });
    });
  }
}

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-04 10:26:35

您可以通过创建依赖关系映射来简化这一点。

例如,地址取决于国家。所以你可以在你的地图上添加这样的东西:

map =‘地址’=> 'country‘

其中您使用的键是窗体控件的键。

然后,您可以做的是订阅表单值更改,每次输入订阅时,您都将遍历所有窗体控件键,并开始检查值,然后根据依赖关系映射决定禁用什么。

这变得很容易扩展,因为您可以在表单控件中添加依赖项,而不需要更改逻辑,您只需要向映射添加一个记录。

我为您编写了一个简单的https://stackblitz.com/edit/angular-ivy-qxfkdz示例。

票数 1
EN

Stack Overflow用户

发布于 2020-08-04 11:06:32

由于表单的顺序性,您的方法可能仍然是您所概述的场景中最好的方法。

但是,另一种方法是直接在表单本身上调用.valueChanges(),而不是单独的表单控件。这将为您提供一个父窗体对象,该对象将在任何嵌套窗体控件更改时发出。然后,您可以将您的逻辑合并到一个订阅调用中。

代码语言:javascript
复制
form.valueChanges.subscribe((value: any) => {
  if (!value.company) {
    form.get("country").reset({ emitEvent: false });
    form.get("country").disable({ emitEvent: false });
  } else {
    form.get("country").enable({ emitEvent: false });
  }

  if (!value.country) {
    form.get("user").reset({ emitEvent: false });
    form.get("user").disable({ emitEvent: false });
  } else {
    form.get("user").enable({ emitEvent: false });
  }

  ...
});

注意:{ emitEvent: false }将阻止窗体触发对其自身的更改检测。这一点很重要,因为如果不这样做,您将陷入无限的更新循环。

由于您的设计形成了一种FormControls链,并且每个if语句实际上都会在链的每个元素上重复,所以我可能会倾向于让getMyForm()返回一个FormArray而不是一个FormGroup。这将允许您对FormControls进行迭代,就像它们存储在数组中一样,并将相同的函数应用于每个函数,这将更有效地扩展。对于FormGroup来说,这有点混乱(但仍然有可能)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63244747

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档