diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index 36eba828b355..3459cb0b5ff0 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -4329,6 +4329,32 @@ describe('MatSelect', () => { }).not.toThrow(); })); + it('should be able to programmatically set an array with duplicate values', fakeAsync(() => { + testInstance.foods = [ + { value: 'steak-0', viewValue: 'Steak' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + { value: 'pizza-1', viewValue: 'Pizza' }, + ]; + fixture.detectChanges(); + testInstance.control.setValue(['steak-0', 'pizza-1', 'pizza-1', 'pizza-1']); + fixture.detectChanges(); + + trigger.click(); + fixture.detectChanges(); + + const optionNodes = Array.from(overlayContainerElement.querySelectorAll('mat-option')); + const optionInstances = testInstance.options.toArray(); + + expect(optionNodes.map(node => node.classList.contains('mat-selected'))) + .toEqual([true, true, true, true, false, false]); + + expect(optionInstances.map(instance => instance.selected)) + .toEqual([true, true, true, true, false, false]); + })); + }); }); diff --git a/src/material/select/select.ts b/src/material/select/select.ts index ec20a48e7685..a3e134067ee8 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -874,6 +874,12 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, */ private _selectValue(value: any): MatOption | undefined { const correspondingOption = this.options.find((option: MatOption) => { + // Skip options that are already in the model. This allows us to handle cases + // where the same primitive value is selected multiple times. + if (this._selectionModel.isSelected(option)) { + return false; + } + try { // Treat null as a special reset value. return option.value != null && this._compareWith(option.value, value);