Robouste
Robouste

Reputation: 3680

Angular Material - Multiple Select - Last selected value

When working with mat-select, you can subscribe to an event "selectionChange".

<mat-select
    [(ngModel)]="value"
    name="someName"
    multiple="true"
    (selectionChange)="handleEvent($event)"
>
    <mat-option
        *ngFor="let val of values"
        [value]="val"
    >
        {{ val }}
    </mat-option>
</mat-select>
handleEvent(event: MatSelectChange) {
    console.log(event.value); // => array of values
}

This will emit a MatSelectChange where you access the current value of the select.

The problem is, when working with multiple selection, the value property will contains an array with all the currently selected values.

What I need, is to know what was the last value the user selected. I have print out the MatSelectChange event to see if there is anything I could use (like, previous values, so I can compare), but, sadly, I don't see anything.

Is it possible to achieve that ?

Upvotes: 2

Views: 3573

Answers (3)

PrazSam
PrazSam

Reputation: 1156

You could have use @DaggeJ's solution along with the Template Driven froms as below.

<mat-select
    [(ngModel)]="value"
    #mySelect="ngModel"
    name="someName"
    multiple="true"">
    <mat-option
        *ngFor="let val of values"
        [value]="val"
    >
        {{ val }}
    </mat-option>
</mat-select>
@ViewChild('mySelect') mySelect: FormControl;
public ngAfterViewInit() {
    this.mySelect.valueChanges.pipe(pairwise()).subscribe(([prev, next]: [any, any]) => {
       console.log(prev + ' -> ' + next);
    });
}

Upvotes: 0

Robouste
Robouste

Reputation: 3680

Since I cannot use ReactiveForm and have to stick with Template Driven, I came up with this solution:

pairwise()

<mat-select
    [(ngModel)]="value"
    name="someName"
    multiple="true"
    (selectionChange)="mySubject.next($event.value)"
>

And on the other side, when subscribing to the subject:


this.mySubject.pipe(startWith(null), pairwise()).subscribe({
    next: (values: number[]) => {
        const previousValue = values[0];
        const currentValue = values[1];

        // previousValue will be null on first call
        const newValue = previousValue === null ? 
            currentValue[0] : currentValue.find((value: number) => !previousValue.includes(value));
    }
)


startWith is there because the subject will not emit any value until it has a previous AND a current value.

Upvotes: 0

DaggeJ
DaggeJ

Reputation: 2191

If you use a FormControl instead of ngModel you can subscribe to the valueChanges Observable to get the previous and next values. There is a post here that covers this topic: Form control valueChanges gives the previous value

Basically what you need to do is to declare a new FormControl in your ts-file;

formControl = new FormControl();

..and bind to it like this;

<mat-select
    [formControl]="formControl"
    name="someName"
    multiple>

...and check for changes like this;

formControl
  .valueChanges
  .pipe(pairwise())
  .subscribe(([prev, next]: [any, any]) => ... );

Upvotes: 2

Related Questions