adelinor
adelinor

Reputation: 813

@HostBinding('disabled') not working with Angular material 12

A custom directive ...

@Directive({
  selector: '[myDirective]',
})
export class MyDirective {

  @HostBinding('disabled')
  disabled = true;

  constructor() { }

  @Input('myDirective')
  set myData(data: string[]) {
    this.disabled = someDirectiveLogic(data);
  }
  
  // ...
}

... has some specific logic to disable a button. When using the directive on a plain HTML button:

<a mat-raised-button color="accent"
  [disabled]="system.selection.length === 0"
>View</a>

<button color="accent"
  [myDirective]="system.selection"
>Pause</button>

The directive works well:

When adding the mat-raised-button property on the Pause button with Angular Material v12, the button always shows as enabled: Material button, no selection and should be disabled

The same code works well with Angular Material v6.3, the disabled attribute set by directive will render well in combination with mat-raised-button.

Cannot we use @HostBinding('disabled') with Angular material 12 ?

Upvotes: 4

Views: 2602

Answers (2)

ravindUwU
ravindUwU

Reputation: 746

Just to clarify the answer by adelinor,

The disabled property of a <button> is a Boolean attribute, the presence of which indicates the true value, and the absence of which indicates the false value.

Testing out how Boolean values bound by Angular are reflected in HTML, notice that [attr.disabled]="true" and [attr.disabled]="false" result in <button disabled="true"> and <button disabled="false"> respectively. The disabled attribute is present on both and therefore they are disabled.

Angular's attribute binding syntax removes the attribute altogether if the bound value is null or undefined, which is why the expression disabled || null works.

Upvotes: 1

adelinor
adelinor

Reputation: 813

After looking at the source code for the Angular Material button, I found a solution which works with a standard button, and a material button.

As in line 70 of button.ts, I noticed that using the host property metadata instead of the HostBinding decorator, works as expected. So the directive is now implemented as:

@Directive({
  selector: '[myDirective]',
  host: {
    '[attr.disabled]': 'disabled || null',
    '[class.mat-button-disabled]': 'disabled',
  },
})
export class MyDirective {

  disabled = true;

  constructor() { }

  @Input('myDirective')
  set myData(data: string[]) {
    this.disabled = someDirectiveLogic(data);
  }
  
  // ...
}

This example is illustrated in stackblitz.com .

Upvotes: 2

Related Questions