2
votes

I got an Angular multiselect mat-select dropdown with checkbox. I used the code from the angular material website and it works. Instead of get a list or array of all selected dropdown items, I prefer to get the item selected or unselected dropdown item. Is that possible.

Here is my html code:

<mat-select multiple [(ngModel)]="myData.countries" (ngModelChange)="onEventDropDownChanged(myData, $event)"> 

<mat-option *ngFor="let country of countries" [value]="country.id" >{{country.name}}</mat-option>

In the typescript, I can see the whats in the parameter

public onEventDropDownChanged(myData: any, event: any) {

}

If the checked/selected dropdown was unchecked, I would like to get that item/id. If the new dropdown item was checked/selected, I like to get the new selected item/id.

Thanks.

2

2 Answers

0
votes

Check this Exmaple

  <mat-form-field>
      <mat-label>Toppings</mat-label>
      <mat-select (ngModelChange)="onEventDropDownChanged($event)" [formControl]="toppings" multiple>
        <mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
      </mat-select>
    </mat-form-field>

onEventDropDownChanged(i) {
console.log('Your Current Selected Item', i)
}
0
votes

Update

Although we are able to get checked/unchecked, but it's really annoying to implement subscription for every mat-select.

So here is solution, I created a Directive which has a event checkboxChanged and it is invoked when mat-option is checked/unchecked

To implement this in your project

1.Simply copy and paste the file mat-select-checkbox-changes.directive.ts from here into you project and import accordingly and start using like below.

<mat-select multiple appMatSelectCheckboxChanges [(ngModel)]="selectedFood" [compareWith]="compareWith" (checkboxChanged)="checkboxChanged($event)">
 <mat-option *ngFor="let food of foods" [value]="food.value">{{food.viewValue}}</mat-option>
</mat-select>

checkboxChanged(evt: { value: Food, isChecked: boolean }) {
 console.log(`${evt.value} is ${evt.isChecked ? 'checked' : 'unchecked'}`);
}

Adding directive code here below(incase links broken)

import { Directive, EventEmitter, Output, OnDestroy } from "@angular/core";
import { MatSelect } from "@angular/material/select";
import { Subscription } from "rxjs";

interface IMatSelectCheckboxChanges {
  value: any;
  isChecked: boolean;
}

@Directive({
  selector: "[appMatSelectCheckboxChanges]"
})
export class MatSelectCheckboxChangesDirective implements OnDestroy {
  @Output() checkboxChanged = new EventEmitter<IMatSelectCheckboxChanges>();
  subscription: Subscription;

  constructor(private matSelect: MatSelect) {
    this.subscription = this.matSelect.optionSelectionChanges.subscribe(matOption => {
        if (matOption.isUserInput) {
          this.checkboxChanged.next({ value: matOption.source.value, isChecked: matOption.source.selected });
        }
      }
    );
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

Original

Use optionSelectionChanges observable.

1.Get mat-select reference

//if there is only one mat-select
@ViewChild(MatSelect) matSelect: MatSelect;

//if there are multiple, then add unique local template variables
@ViewChild('#favFood') favFoodselect: MatSelect;
@ViewChild('#favAnimal') favAnimalselect: MatSelect;

2.Subscribe to the changes

this.subscription = this.matSelect.optionSelectionChanges.subscribe(matOption => {
 if (matOption.isUserInput) {
  console.log(`${matOption.source.viewValue} is ${matOption.source.selected ? 'checked' : 'unchecked'}`);
 }
});

Some Details

The above subscription will also called, if you initially assign any value(default value)

So to prevent that, add if check using matOption.isUserInput


Don't forget to unsubscribe observable

ngOnDestroy() {
 if (this.subscription) {
  this.subscription.unsubscribe();
 }
}

Stackblitz Demo