MatCheckbox preventDefault() and event.checked value

Viewed 11042

How can I achieve a Material checkbox so It won't get checked/unchecked by default (eg. calling preventDefault() on the event) and also get the checked value from the event?

It seems like I can only achieve one of the conditions. Using the (click) event I cannot get the checkbox's value and using the (change) event I can't prevent the default checkbox value change (I will only change the checkbox value if the underlying HTTP request was successful).

Stackblitz: https://stackblitz.com/edit/matcheckbox-checked

<mat-checkbox 
  [checked]="checked"   
  (click)="onClick($event)"
>onClick me!</mat-checkbox>

<br/>

<mat-checkbox 
  [checked]="checked"
  (change)="onChange($event); false"
>onChange me!</mat-checkbox>

export class CheckboxOverviewExample {
  checked: boolean = false;

  onClick(event) {
    event.preventDefault();
    console.log('onClick event.checked ' + event.checked);
    console.log('onClick event.target.checked '+event.target.checked);
  }

  onChange(event) {
    // can't event.preventDefault();
    console.log('onChange event.checked '+event.checked);
  }
}

The (click) event prints undefined values, but successfully prevents the event propagation, the (change) event prints the value but will propagate the event.

Connected issues:

5 Answers

In my personal case, I have to code for mouse and also for keyboard events, in case you care about accessibility you know :)

if you hit 'Space' it with still check, so (click) is not enough, you also need to include (keydown). No just that but after I fixed the issue with the Space, I noticed that it will also block the Tab which I need it to navigate with the keyboard, so I just had to add a little code for that

      <mat-checkbox [checked]="descendantsAllSelected(node)" 
        [indeterminate]="descendantsPartiallySelected(node)"
        (click)="toggleDescendants(node,$event)"
        (keydown)="toggleDescendants(node,$event)"
        >
        {{node.name}}
      </mat-checkbox>

In Code

  toggleDescendants(node, $event) {
    this._logger.debug('toggleDescendants()');
    this.treeControl.toggleDescendants(node);
    if ($event.code !== 'Tab') {
      $event.preventDefault();
    }
  }

You can prevent default action on "change" with a provider in the component:

providers: [{
    provide: MAT_CHECKBOX_DEFAULT_OPTIONS, 
    useValue: { clickAction: 'noop' } as MatCheckboxDefaultOptions
}]

(source: https://material.angular.io/components/checkbox/overview#noop)

and you can bind the checked to a local variable (or a getter function)

<mat-checkbox
(click)="changeValue()"
[checked]="theValue"
>
   Whatever
</mat-checkbox>

So, in the code, for examle, you use theValue as the value, and set that value programmatically. This way you do not need to receive the checkbox state as a parameter of the click method, you can access it from theValue.

theValue: boolean = false;

changeValue(): void {
    this.theValue = !this.theValue
}

try indeterminate

check
Toggle checked value of the checkbox, ignore indeterminate value. If the checkbox is in indeterminate state, the checkbox will display as an indeterminate checkbox regardless the checked value.

check-indeterminate
Default behavior of mat-checkbox. Always set indeterminate to false when user click on the mat-checkbox. This matches the behavior of native "input type="checkbox""

https://material.angular.io/components/checkbox/overview#-code-check-code-

We cannot control the default behavior of checkbox and event properties. You can create 2 image icons with checked and unchecked state, toggle it based on value.

Related