Here is how I would do this. Since I don't know what the shape of your data, i just created some, you'll have to adapt to your case.
Note that the answer of @barrilocho is correct, but your problem is that you are using the wrong event.
Your selectionChange is triggered each time you check an item, with all the checked items in its event's value, so http calls accumulate.
Try using closed event this way :
<mat-select multiple (closed)="getModels(cars.value)" #cars>
Is is triggered only when the panel close, and therefore iterate over your checked items. closed event is just a small optimization for a bigger problem if you have a lot of data.
Repro on Stackblitz and here is the code :
service :
getModel(car: string) {
const models = [
{ car: "car1", model: "model1" },
{ car: "car2", model: "model2" },
{ car: "car3", model: "model3" },
{ car: "car3", model: "model4" }
];
// Could be a filter, adapt as you wish
return of(models.filter(m => m.car === car));
}
TS :
export class SelectValueBindingExample {
vehicles = ["car1", "car2", "car3"];
models$: Observable<Array<any>>;
constructor(private _modelsService: ModelsService) {}
getModels(selectedCars: Array<any>) {
const obs$: Array<Observable<any>> = [];
// Would be better if you could find a way to only request the new items and remove the unckecked ones
selectedCars.forEach(car => obs$.push(this._modelsService.getModel(car)));
this.models$ = forkJoin(obs$).pipe(
map(values => values.flat()) // flatten an array of array
);
}
}
HTML :
<mat-form-field appearance="fill">
<mat-label>Choose your cars</mat-label>
<mat-select multiple (selectionChange)="getModels(cars.value)" #cars>
<mat-option *ngFor="let item of vehicles" [value]="item">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>
<br /><br />
<mat-form-field appearance="fill">
<mat-label>Choose your model</mat-label>
<mat-select multiple (onClose)="getModels($event)">
<mat-option *ngFor="let model of models$ | async" [value]="model">
{{model.car}} - {{model.model}}
</mat-option>
</mat-select>
</mat-form-field>
Here I give you a solution using observable directly (Note the async pipe in the html). This is just how I would do it but first, I'd suggest, if possible, to rework your campainService.getModels method to actually accept multiple items and treat everything in the back end. you'll en up with only one http call per changes, which would be way better.