Skip to content

Commit e269b2a

Browse files
author
Sam Severance
committed
fix(list): determine if option value changed (#19828)
When the value of a `mat-list-option` is updated, the `mat-selection-list` `compareWith` function should be used to compare the new value with the old value. This prevents options from being incorrectly unselected when the option value is updated.
1 parent db4b0cd commit e269b2a

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,39 @@ describe('MatSelectionList without forms', () => {
801801
});
802802
});
803803

804+
describe('with changing option value', () => {
805+
let fixture: ComponentFixture<SelectionListWithChangingOptionValue>;
806+
let selectionList: MatSelectionList;
807+
let listOption: MatListOption;
808+
809+
beforeEach(async(() => {
810+
TestBed.configureTestingModule({
811+
imports: [MatListModule],
812+
declarations: [SelectionListWithChangingOptionValue],
813+
});
814+
815+
TestBed.compileComponents();
816+
}));
817+
818+
beforeEach(() => {
819+
fixture = TestBed.createComponent(SelectionListWithChangingOptionValue);
820+
fixture.detectChanges();
821+
822+
selectionList = fixture.debugElement.query(By.directive(MatSelectionList))!.componentInstance;
823+
listOption = fixture.debugElement.query(By.directive(MatListOption))!.componentInstance;
824+
});
825+
826+
it('should use `compareWith` function when updating option selection state', () => {
827+
expect(selectionList.selectedOptions.isSelected(listOption)).toBeTrue();
828+
fixture.componentInstance.value = {id: 1};
829+
fixture.detectChanges();
830+
expect(selectionList.selectedOptions.isSelected(listOption)).toBeTrue();
831+
fixture.componentInstance.value = {id: 2};
832+
fixture.detectChanges();
833+
expect(selectionList.selectedOptions.isSelected(listOption)).toBeFalse();
834+
});
835+
});
836+
804837
describe('with option disabled', () => {
805838
let fixture: ComponentFixture<SelectionListWithDisabledOption>;
806839
let listOptionEl: HTMLElement;
@@ -1668,6 +1701,20 @@ class SelectionListWithCustomComparator {
16681701
}
16691702

16701703

1704+
@Component({
1705+
template: `
1706+
<mat-selection-list [compareWith]="compareWith">
1707+
<mat-list-option [value]="value" [selected]="value.id === 1">
1708+
One
1709+
</mat-list-option>
1710+
</mat-selection-list>`
1711+
})
1712+
class SelectionListWithChangingOptionValue {
1713+
compareWith = (o1: any, o2: any) => o1 && o2 && o1.id === o2.id;
1714+
value = {id: 1};
1715+
}
1716+
1717+
16711718
@Component({
16721719
template: `
16731720
<mat-selection-list>

src/material/list/selection-list.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ export class MatListOption extends _MatListOptionMixinBase implements AfterConte
145145
@Input()
146146
get value(): any { return this._value; }
147147
set value(newValue: any) {
148-
if (this.selected && newValue !== this.value && this._inputsInitialized) {
148+
if (
149+
this.selected &&
150+
!this.selectionList.compareWith(newValue, this.value) &&
151+
this._inputsInitialized
152+
) {
149153
this.selected = false;
150154
}
151155

0 commit comments

Comments
 (0)