【问题标题】:Disable Form Group via directive通过指令禁用表单组
【发布时间】:2021-10-26 14:38:27
【问题描述】:

我在尝试实现一个指令时遇到了麻烦,我可以在具有 [formGroup] 属性的元素上使用该指令来设置禁用整个表单组及其表单控件的条件,而不是强制调用 this.formGroup.disable()

我有一个通过搜索网络获得的表单控件的工作指令:

import { Directive, Input } from "@angular/core";
import { NgControl } from "@angular/forms";

// use this directive instead manually enabling and disabling with reactive forms
@Directive({
  selector: "([formControlName], [formControl])[disabledControl]",
})
export class DisabledControlDirective {
  @Input() set disabledControl(condition: boolean) {
    if (this.disabled !== undefined) {
      this.toggleControl(condition);
    }
    this.disabled = condition;
  }

  disabled: boolean;

  constructor(private readonly ngControl: NgControl) {}

  ngOnInit() {
    this.toggleControl(this.disabled);
  }

  toggleControl(condition: boolean) {
    const action = condition ? "disable" : "enable";
    this.ngControl.control[action]();
  }
}

我为表单组尝试了类似的方法:

import { Directive, Input } from "@angular/core";
import { ControlContainer } from "@angular/forms";

@Directive({
  selector: "([formGroup])[disabledGroup]",
})
export class DisabledGroupDirective {
  @Input() set disabledGroup(condition: boolean) {
    if (this.disabled !== undefined) {
      this.toggleGroup(condition);
    }
    this.disabled = condition;
  }

  disabled: boolean;

  constructor(private readonly controlContainer: ControlContainer) {}

  ngOnInit() {
    this.toggleGroup(this.disabled);
  }

  toggleGroup(condition: boolean) {
    const action = condition ? "disable" : "enable";
    this.controlContainer.control[action]();
  }
}

但表单组实际上并没有正确禁用。我在 toggleGroup() 方法上设置了一个断点,之后表单组的状态为“已禁用”,但在恢复应用程序时,表单完成加载并且未被禁用。我随后通过单击按钮将表单组注销,状态再次为“无效”,而不是“禁用”。

有解决这个问题的想法吗?

编辑: 我对此做了一个非常基本的 Stackblitz,它似乎可以自己工作: https://stackblitz.com/edit/angular-ivy-owlvqu?file=src/app/app.component.ts

编辑2: 没有其他东西可以操纵该表单组,除了有一次它是通过 ngOnInit() 中的 addControl() 添加到父 formGroup 的,但即使在 stackblitz 中取消禁用仍然不起作用,我可以不知道什么可能会重置其状态。

我尝试在 group 指令中使用 ngAfterViewInit() 而不是 ngOnInit(),奇怪的是,它有效,但它禁用了。我不知道这是否是最干净的解决方案,最好知道 formGroup 会进一步发生什么,但我的代码中没有任何东西可以操纵它。

【问题讨论】:

    标签: angular typescript angular-reactive-forms angular-directive


    【解决方案1】:

    如果将指令应用到 f​​ormGroup,则需要在构造函数中访问 formGroup。为此,您注入 FormGroupDirective

      constructor(private readonly form: FormGroupDirective) {}
    
    我们可以让我们的函数切换接收 FormGroup。 FormGroup 是一个对象,因此我们需要使用 Object.keys 进行迭代
      toggleGroup(form: FormGroup, condition: boolean) {
        const action = condition ? 'disable' : 'enable';
        Object.keys(form.controls).forEach(key => {
            const control = form.get(key);
            control[action]();
          });
        }
      }
    

    在我们的输入中,我们调用传递 FormGroup 的函数(它位于 FormGroupDirective.form 下

      @Input() set disabledGroup(condition: boolean) {
        this.toggleGroup(this.form.form, condition);
        this.disabled = condition;
      }
    

    好吧,如果只有一个 FormControls 的 FormGroup,这个指令就可以工作,但是如果我们的 FormGroup 中有一个子 FormGroup 会发生什么?那么 FormArray 呢?好吧,我们需要考虑是 FormArray 还是 FormGroup,因为我们以不同的方式迭代。无论如何,我们的函数应该是递归的。所以,我们可以像这样改变我们的函数

      toggleGroup(form: FormGroup | FormArray, condition: boolean) {
        const action = condition ? 'disable' : 'enable';
        if (form instanceof FormArray) {  //if is a FormArray
          form.controls.forEach(x => {
            if (x instanceof FormControl) x[action]();
            if (x instanceof FormGroup || x instanceof FormArray)
             this.toggleGroup(x, condition);
          });
        } else {  //if is a FormGroup
          Object.keys(form.controls).forEach(key => {
            const control = form.get(key);
            if (control instanceof FormControl) control[action]();
            if (control instanceof FormGroup || control instanceof FormArray)
             this.toggleGroup(control, condition);
          });
        }
      }
    

    您在此stackblitz 中有指令

    只用(看formGroup在form.form下)

      @Input() set disabledGroup(condition: boolean) {
        const action = condition ? 'disable' : 'enable';
        this.form.form[action]();
      }
    

    【讨论】:

    • 但这并不是真正的问题。我已经在构造函数中注入了一个ControlContainer 实例,它只是FormGroupDirective 的超类,所以两者都可以工作。并且没有任何需要遍历 FormGroup 的所有子元素来禁用它们,如果你只是单独禁用 FormGroup,Reactive Forms 已经这样做了。
    • @Muffin,我的好!!,没关系,使用 FormGroupDirective 的属性“form”访问表单非常简单(感谢您的建议)
    猜你喜欢
    • 1970-01-01
    • 2022-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    相关资源
    最近更新 更多