1
votes

I have several nested reusable components with their respective state in their own reactive forms. When I disable the parent component using the formControl-methods disable()/enable(), I want to enable or disable all child formControls.

Background: In reactive forms, the HTML attribute disabled is controlled from the formControl itself:

this.formGroup = new FormGroup({ 
  control: new FormControl({ value: '', disabled: true }) 
});

And the toggling of enable/disable is also done like so:

this.formGroup.get('control')!.enable(); // Or disable()

The formGroup will set the attribute disabled inside the DOM for you.

Problem: The problem I am having is that when I use enable()/disable(), the setter of the child disabled @Input() never gets called. I have no way of propagating the enabling/disabling to all child components.

@Component({
  template: `
    <ng-container [formGroup]="formGroup">
      <child-component formControlName="control"></child-component>
    </ng-container>
`})
export class ParentComponent { 

  ...

  method(): void {
    this.formGroup.get('control')!.enable(); // Or disable()
  }
}

And inside the child component, where I am failing to listen to the enabling of the parent component:

@Component(...)
export class ChildComponent implements ControlValueAccessor {  

  @Input()
  get disabled(): boolean {
    return this._disabled;
  }
  // This setter never gets called as it would've using a normal @Input().
  set disabled(val: boolean) {
    this._disabled = val;
  }
}

How can I listen to enabling/disabling within ChildComponent in the above example?

1
can you share parent html where you binding input propertyChellappan வ
@Chellappan I've added a template. All my child-components implement ControlValueAccessor.blid

1 Answers

1
votes

This is how I ended up letting ChildComponent know that ParentComponent had enabled/disabled it:

Solution 1:

const disableChange$ = this.ngControl.statusChanges.pipe(
    map(status => status === 'DISABLED'),
    distinctUntilChanged()
)

Where ngControl is injected into the constructor of ChildComponent.

Edit:

Solution 2 (much better one):

setDisabledState(isDisabled: boolean): void {
  this.disabled = isDisabled;
  this.stateChanges.next();
}

Use setDisabledState of the ControlValueAccessor interface in ChildComponent to set the disabled state.