【问题标题】:Angular Reactive Forms - Let Nested Child Determine Enable/DisableAngular Reactive Forms - 让嵌套子项确定启用/禁用
【发布时间】:2019-12-05 05:06:49
【问题描述】:

我有一个嵌套的 Angular 反应形式。

子项有 2 个属性,第二个属性根据第一个属性的值启用或禁用。

父表单有一个编辑按钮,可以通过 this.parentForm.enable().

我的问题是这无论如何都会启用第二个子字段,并且不使用子字段中的逻辑来确定是否应该启用或禁用它。

对于在子级中启用/禁用逻辑的反应式表单的建议方法是什么?我尝试使用 [disabled] 但它不起作用,我收到警告说我不应该这样做.

这是一个 stackblitz 的示例问题。

edit 被点击时,如果Yes 被选中,它应该只启用最后一个输入。如果选中No,则应该禁用它。

【问题讨论】:

  • 你应该把你的代码放在你的问题中。
  • @bryan60 而不是在堆栈闪电战中?
  • 两者都推荐,链接在未来可能会变坏,但它们现在很有帮助。

标签: angular angular-reactive-forms


【解决方案1】:

所以在你的控制器中添加一个这样的函数:

 private setChildState() { 
    // this function gets the ctrl to enable/disable and does so based on the value
    const v = this.parentForm.get('typeDetails').get('identity').value;
    let ctrl = this.parentForm.get('typeDetails').get('identityname');
    if (v === 'yes') {
      ctrl.enable();
    } else {
      ctrl.disable();
    }
 }

这是设置您的子表单启用/禁用状态,然后只需添加以下几行:

这在你的 ngOnViewInit() 中

// this listens to value changes and updates form state
this.parentForm.get('typeDetails').get('identity').valueChanges.subscribe(v => {
  this.setChildState();
});

然后在你的编辑功能中:

this.setChildState();

固定闪电战:https://stackblitz.com/edit/angular-bwfn35?file=src/app/app.component.ts

编辑:

如果您想将这一切(大部分)保留在孩子身上,请将您的孩子改为:

  ngOnInit() {
    this.identifyForm.get('identity').valueChanges.subscribe(v => {
      this.setState();
    })
  }

  setState() {
    const v = this.identifyForm.get('identity').value;
    let ctrl = this.identifyForm.get('identityname');
    if (v === 'yes') {
      ctrl.enable();
    } else {
      ctrl.disable();
    }
  }

然后将其添加到父级中的编辑功能:

this.childComponent.setState();

【讨论】:

  • 这确实有效,但它会将孩子的逻辑泄露给父母。这个孩子每次都会在多个地方使用相同的启用/禁用逻辑,所以我必须在每个父级中复制 setChildState。是否可以在没有每个父级的子逻辑的情况下做到这一点?
  • 就我而言,Bryne 的解决方案帮助我解决了我的问题。
【解决方案2】:

将 Radio Group 代码移动到您的父组件并订阅更改

基于值 yesno

启用和禁用子组件表单控件

提交堆栈闪电战:https://stackblitz.com/edit/angular-kszjwj

【讨论】:

  • 这会将孩子的验证逻辑泄漏到父母中。当孩子以多种形式使用时成为一个真正的问题。
【解决方案3】:

另一个方法是改进这个stackoverflow answer的启用指令

我们将改进指令以允许禁用不仅是控件,还允许禁用表单内的所有控件。

@Directive({
  selector: '[disableControl]'
})
export class DisableControlDirective {
  @Input() set disableControl(condition: boolean) {
    if (this.ngControl) { //if is an ngControl
      if (condition)
        this.ngControl.control.disable();
      else
        this.ngControl.control.enable();
    }
    if (this.controls) { //if is a formGroup, we ask about the inners controls
      this.controls.forEach((x: any) => {
        let control:boolean=false;
        if (this.innerControl) //we check if the control has
                               //his own DisableControlDirective
          control=(this.innerControl.find(inner=>x==inner.ngControl)!=null)

        if (!control) { //if it has not a own DisabledControlDirective
          if (condition)
            x.control.disable();
          else
            x.control.enable()
        }
      })
    }
  }
  @ContentChildren(NgControl) controls: QueryList<NgControl>
  @ContentChildren(DisableControlDirective)
             innerControl:QueryList<DisableControlDirective>
  //see that make public ngControl to use when check if a innerControl has 
  //the directive
  constructor(@Optional() public ngControl: NgControl) {}
}

如果我们将指令应用于 fromGroup,则禁用/启用所有内部控件。为了获得内部控制,我们使用@ContentChildren(NgControl)。当我们注入 NgControl 时,我们需要输入 @Optional(),因为在 FormGroup 中我们没有 NgControl - 请记住 NgControl 是任何具有 [formControlName]、[NgModel] 或 [formControl] 指令的东西

我们需要检查我们的内部控件是否没有 [disableControl] 指令。在这种情况下,我们需要跨越这个控件。为此,我们需要使用@ContentChildren(DisableControlDirective) 获取这些控件并进行检查。

我们的表单变得非常“简单”,但是我们将编辑模式作为@Input 传递给孩子

<form [formGroup]="parentForm" [disableControl]="!editMode" (ngSubmit)="onSave()">
  <input formControlName="id">
  <input formControlName="name">
  <app-child-component [editMode]="editMode"></app-child-component>
</form>

//and our children component

<form [formGroup]="identifyForm" [disableControl]="!editMode">
  <input type="radio" name="identity" value="yes" formControlName="identity"> Yes
  <input type="radio" name="identity" value="no" formControlName="identity" > No

  <input formControlName="identityname" 
     [disableControl]="!editMode || identifyForm.get('identity').value=='no'">
</form>

我们可以在这个stackblitz看到最终结果

【讨论】:

    猜你喜欢
    • 2021-06-07
    • 1970-01-01
    • 2020-08-19
    • 2022-10-08
    • 1970-01-01
    • 2019-06-22
    • 2019-08-13
    • 2020-07-24
    • 1970-01-01
    相关资源
    最近更新 更多