Skip to content

Commit d95d10d

Browse files
committed
fix(select): not marking options as selected correctly when setting value with duplicates
Fixes `mat-select` not marking all of the options as selected, when an array with duplicate values is assigned programmatically. Fixes #13179.
1 parent 14c4dba commit d95d10d

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/material/select/select.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4329,6 +4329,32 @@ describe('MatSelect', () => {
43294329
}).not.toThrow();
43304330
}));
43314331

4332+
it('should be able to programmatically set an array with duplicate values', fakeAsync(() => {
4333+
testInstance.foods = [
4334+
{ value: 'steak-0', viewValue: 'Steak' },
4335+
{ value: 'pizza-1', viewValue: 'Pizza' },
4336+
{ value: 'pizza-1', viewValue: 'Pizza' },
4337+
{ value: 'pizza-1', viewValue: 'Pizza' },
4338+
{ value: 'pizza-1', viewValue: 'Pizza' },
4339+
{ value: 'pizza-1', viewValue: 'Pizza' },
4340+
];
4341+
fixture.detectChanges();
4342+
testInstance.control.setValue(['steak-0', 'pizza-1', 'pizza-1', 'pizza-1']);
4343+
fixture.detectChanges();
4344+
4345+
trigger.click();
4346+
fixture.detectChanges();
4347+
4348+
const optionNodes = Array.from(overlayContainerElement.querySelectorAll('mat-option'));
4349+
const optionInstances = testInstance.options.toArray();
4350+
4351+
expect(optionNodes.map(node => node.classList.contains('mat-selected')))
4352+
.toEqual([true, true, true, true, false, false]);
4353+
4354+
expect(optionInstances.map(instance => instance.selected))
4355+
.toEqual([true, true, true, true, false, false]);
4356+
}));
4357+
43324358
});
43334359
});
43344360

src/material/select/select.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,12 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
874874
*/
875875
private _selectValue(value: any): MatOption | undefined {
876876
const correspondingOption = this.options.find((option: MatOption) => {
877+
// Skip options that are already in the model. This allows us to handle cases
878+
// where the same primitive value is selected multiple times.
879+
if (this._selectionModel.isSelected(option)) {
880+
return false;
881+
}
882+
877883
try {
878884
// Treat null as a special reset value.
879885
return option.value != null && this._compareWith(option.value, value);

0 commit comments

Comments
 (0)