Skip to content

Commit bef9a17

Browse files
crisbetovivian-hu-zz
authored andcommitted
fix(list): selection list not marking options as selected correctly when setting value with duplicates (#13363)
Along the same lines as #13361. Fixes the selection list not marking all selected options correctly when an array with duplicate values is assigned programmatically.
1 parent 56f2e50 commit bef9a17

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

src/lib/list/selection-list.spec.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ describe('MatSelectionList with forms', () => {
789789

790790
expect(fixture.componentInstance.selectedOptions).toEqual(['opt2', 'opt3']);
791791

792-
fixture.componentInstance.renderLastOption = false;
792+
fixture.componentInstance.options.pop();
793793
fixture.detectChanges();
794794
tick();
795795

@@ -829,6 +829,20 @@ describe('MatSelectionList with forms', () => {
829829
expect(fixture.componentInstance.modelChangeSpy).not.toHaveBeenCalled();
830830
});
831831

832+
it('should be able to programmatically set an array with duplicate values', fakeAsync(() => {
833+
fixture.componentInstance.options = ['one', 'two', 'two', 'two', 'three'];
834+
fixture.detectChanges();
835+
tick();
836+
837+
listOptions = fixture.debugElement.queryAll(By.directive(MatListOption))
838+
.map(optionDebugEl => optionDebugEl.componentInstance);
839+
840+
fixture.componentInstance.selectedOptions = ['one', 'two', 'two'];
841+
fixture.detectChanges();
842+
tick();
843+
844+
expect(listOptions.map(option => option.selected)).toEqual([true, true, true, false, false]);
845+
}));
832846

833847
});
834848

@@ -1076,15 +1090,13 @@ class SelectionListWithTabindexBinding {
10761090
@Component({
10771091
template: `
10781092
<mat-selection-list [(ngModel)]="selectedOptions" (ngModelChange)="modelChangeSpy()">
1079-
<mat-list-option value="opt1">Option 1</mat-list-option>
1080-
<mat-list-option value="opt2">Option 2</mat-list-option>
1081-
<mat-list-option value="opt3" *ngIf="renderLastOption">Option 3</mat-list-option>
1093+
<mat-list-option *ngFor="let option of options" [value]="option">{{option}}</mat-list-option>
10821094
</mat-selection-list>`
10831095
})
10841096
class SelectionListWithModel {
10851097
modelChangeSpy = jasmine.createSpy('model change spy');
10861098
selectedOptions: string[] = [];
1087-
renderLastOption = true;
1099+
options = ['opt1', 'opt2', 'opt3'];
10881100
}
10891101

10901102
@Component({

src/lib/list/selection-list.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,21 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements Focu
473473
private _setOptionsFromValues(values: string[]) {
474474
this.options.forEach(option => option._setSelected(false));
475475

476-
values
477-
.map(value => {
478-
return this.options.find(option =>
479-
this.compareWith ? this.compareWith(option.value, value) : option.value === value);
480-
})
481-
.filter(Boolean)
482-
.forEach(option => option!._setSelected(true));
476+
values.forEach(value => {
477+
const correspondingOption = this.options.find(option => {
478+
// Skip options that are already in the model. This allows us to handle cases
479+
// where the same primitive value is selected multiple times.
480+
if (option.selected) {
481+
return false;
482+
}
483+
484+
return this.compareWith ? this.compareWith(option.value, value) : option.value === value;
485+
});
486+
487+
if (correspondingOption) {
488+
correspondingOption._setSelected(true);
489+
}
490+
});
483491
}
484492

485493
/** Returns the values of the selected options. */

0 commit comments

Comments
 (0)