Angular – Uncheck active Angular Material toggle buttons on click

angularangular-material2

I need to modify the functionality of the standard Angular Material toggle button component, so that clicking an active button returns the component to a state where no buttons are active. This has two steps:

  • Updating the value of the toggle group
  • Changing the 'checked' parameter of the clicked button to false

I've tried several approaches, e.g.

Template:

<mat-button-toggle-group #group="matButtonToggleGroup">
    <mat-button-toggle #no_btn value="no" (click)="update_toggle(group,no_btn)">No</mat-button-toggle>
    <mat-button-toggle #yes_btn value="yes" (click)="update_toggle(group,yes_btn)">Yes</mat-button-toggle>
</mat-button-toggle-group>

JS:

update_toggle(group,button){
    if(group.value==""){
        group.value = button.value;
    }
    else
    {
        group.value = "";
    }
button.checked=!button.checked;
}

But this doesn't update the 'checked' value of the buttons, I guess because the group value set by update_toggle() is in conflict with the user action of clicking the button.

The only approach which has worked is:

<mat-button-toggle-group #group="matButtonToggleGroup">
    <mat-button-toggle #no_btn value="no" (click)="update_toggle(group,no_btn)" (click)="group.value=='no' ? checked=false : checked=false">No</mat-button-toggle>
    <mat-button-toggle #yes_btn value="yes" (click)="update_toggle(group,yes_btn)" (click)="group.value=='yes' ? checked=false : checked=false">Yes</mat-button-toggle>
</mat-button-toggle-group>

But two click events on a single button feels very hacky, especially as the ternary in the second click is opposite to what it instinctively should be.

Any suggestions for a better approach?

I've tried:

@ViewChildren('no_btn') no_btn: ElementRef;

and then:

this.no_btn['_results'][k]['_inputElement']['nativeElement']['checked']=false;

But the result doesn't seem to be any different from passing the button reference in the function; clicking the button a second time doesn't uncheck it. Disabling does work, so I think my code is correct:

this.no_btn['_results'][k]['_inputElement']['nativeElement']['disabled']=true;

Best Answer

A simple generic solution that doesn't require resorting to events on each button or click events at all, and doesn't require ViewChildren or hard-coding value checks, is to use the button toggle in multiple mode and manage selections through the group change event. The change event gives you all you need so there is no need to access child components directly:

<mat-button-toggle-group multiple (change)="toggleChange($event)">
    <mat-button-toggle value="no">No</mat-button-toggle>
    <mat-button-toggle value="yes">Yes</mat-button-toggle>
</mat-button-toggle-group>

toggleChange(event) {
    let toggle = event.source;
    if (toggle) {
        let group = toggle.buttonToggleGroup;
        if (event.value.some(item => item == toggle.value)) {
            group.value = [toggle.value];
        }
    }
}

Here it is on Stackblitz.

Related Topic