What actually triggers ControlValueAccessor's setDisabledState function?

Viewed 1434

I'm trying to figure out how to implement the setDisabledState function that is a part of the ControlValueAccessor interface, but I can't figure out how to actually trigger the function from outside of the component itself.

Within the component I have

control = new FormControl();

setDisabledState(isDisabled: boolean): void {
    this._renderer.setProperty(this.formField.nativeElement, 'disabled', isDisabled);
  }

This sets my disabled styling fine if I do the below inside the NgOnInit of my component. But I want to be able to control the disabled state of my component through property binding.

this.tenantListFormControl.disable();

However, nothing actually triggers the function.

I've tried

<app-custom-control [attr.disabled]="true"></app-custom-control>
<app-custom-control disabled></app-custom-control>
<app-custom-control [disabled]="true"></app-custom-control> 

The last one isn't even valid as "Property disabled is not provided by any applicable directives etc..." as I don't have @Input() disabled anywhere on the component. Which wouldn't help anyway because what am I supposed to do with that once I've set it, I can't subscribe to it and trigger the setDisabledState function that way as it's not an observable.

How do I actually trigger this function and disable my component?

3 Answers

Jake, to disable a FormControl (If you're using reactive Forms) you need use the method disable() -or create as disabled- so using [disable] or [attr.disable] don't call to your function setDisabledState. you can think in a @Input like

@Input() set disabled(value)
{
   this.setDisabledState(value)
}

But this "break" the Angular Reactive Form. If you use [disabled]="true" in a Reactive Form you can see and advertisment: "It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true when you set up this control in your component class, the disabled attribute will actually be set in the DOM for you. We recommend using this approach to avoid 'changed after checked' errors."

The most closer "Angular way" to disable a FormControl is using a directive, see e.g. this SO

I think you are misunderstanding how to use ControlValueAccessor.

This is from the ControlValueAccessor class

  /**
   * @description
   * Function that is called by the forms API when the control status changes to
   * or from 'DISABLED'. Depending on the status, it enables or disables the
   * appropriate DOM element.
   *
   * @usageNotes
   * The following is an example of writing the disabled property to a native DOM element:
   *
   * ```ts
   * setDisabledState(isDisabled: boolean): void {
   *   this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
   * }
   * ```
   *
   * @param isDisabled The disabled status to set on the element
   */
  setDisabledState?(isDisabled: boolean): void;

You trigger it by toggling the bound form control's disabled property. The bound form control exists in the parent component.

<app-custom-control [formControl]="control"></app-custom-control>

When the form control bound to this component has its disabled state toggled the 'setDisabledState' function will be called.

Unsure without seeing more of your code, but I believe you do need

@Input() disabled: boolean = false;

With some logic in your component / view that actually handles what should happen when it is disabled. For example I have a custom control that is wrapping some logic around a button so I have attribute [disabled]="disabled" on the button that is in my view.

If that doesn't help then I'd need to know what is the custom control for, and how would Angular / the browser know how to disable it?

Related