Skip to content

Commit

Permalink
fix(select): not marking options as selected correctly when setting v…
Browse files Browse the repository at this point in the history
…alue with duplicates (#13361)

Fixes `mat-select` not marking all of the options as selected, when an array with duplicate values is assigned programmatically.

Fixes #13179.

(cherry picked from commit 07faecc)
  • Loading branch information
crisbeto authored and annieyw committed Feb 9, 2021
1 parent 1c16d91 commit 4083b10
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/material/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4640,6 +4640,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]);
}));

});

it('should be able to provide default values through an injection token', fakeAsync(() => {
Expand Down
6 changes: 6 additions & 0 deletions src/material/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,12 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
*/
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);
Expand Down

0 comments on commit 4083b10

Please sign in to comment.