Skip to content

Commit f93d0f4

Browse files
crisbetojelbourn
authored andcommitted
fix(selection-list): repeated preselected items not appearing as selected with OnPush parent (#10100)
Fixes preselected options, rendered with via `NgFor`, inside a component with `OnPush` change detection, not appearing as selected. Fixes #10090.
1 parent 1576a99 commit f93d0f4

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

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

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
dispatchEvent,
66
dispatchKeyboardEvent,
77
} from '@angular/cdk/testing';
8-
import {Component, DebugElement} from '@angular/core';
9-
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
8+
import {Component, DebugElement, ChangeDetectionStrategy} from '@angular/core';
9+
import {async, ComponentFixture, fakeAsync, TestBed, tick, flush} from '@angular/core/testing';
1010
import {By} from '@angular/platform-browser';
1111
import {
1212
MatListModule,
@@ -592,7 +592,8 @@ describe('MatSelectionList with forms', () => {
592592
SelectionListWithModel,
593593
SelectionListWithFormControl,
594594
SelectionListWithPreselectedOption,
595-
SelectionListWithPreselectedOptionAndModel
595+
SelectionListWithPreselectedOptionAndModel,
596+
SelectionListWithPreselectedFormControlOnPush,
596597
]
597598
});
598599

@@ -800,6 +801,20 @@ describe('MatSelectionList with forms', () => {
800801
expect(fixture.componentInstance.selectedOptions).toEqual(['opt1', 'opt2']);
801802
}));
802803

804+
it('should show the item as selected when preselected inside OnPush parent', fakeAsync(() => {
805+
const fixture = TestBed.createComponent(SelectionListWithPreselectedFormControlOnPush);
806+
fixture.detectChanges();
807+
808+
const option = fixture.debugElement.queryAll(By.directive(MatListOption))[1];
809+
810+
fixture.detectChanges();
811+
flush();
812+
fixture.detectChanges();
813+
814+
expect(option.componentInstance.selected).toBe(true);
815+
expect(option.nativeElement.querySelector('.mat-pseudo-checkbox-checked')).toBeTruthy();
816+
}));
817+
803818
});
804819
});
805820

@@ -949,3 +964,17 @@ class SelectionListWithPreselectedOption {
949964
class SelectionListWithPreselectedOptionAndModel {
950965
selectedOptions = ['opt1'];
951966
}
967+
968+
969+
@Component({
970+
changeDetection: ChangeDetectionStrategy.OnPush,
971+
template: `
972+
<mat-selection-list [formControl]="formControl">
973+
<mat-list-option *ngFor="let opt of opts" [value]="opt">{{opt}}</mat-list-option>
974+
</mat-selection-list>
975+
`
976+
})
977+
class SelectionListWithPreselectedFormControlOnPush {
978+
opts = ['opt1', 'opt2', 'opt3'];
979+
formControl = new FormControl(['opt2']);
980+
}

src/lib/list/selection-list.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,19 @@ export class MatListOption extends _MatListOptionMixinBase
168168
}
169169

170170
ngOnInit() {
171-
if (this._selected) {
172-
// List options that are selected at initialization can't be reported properly to the form
173-
// control. This is because it takes some time until the selection-list knows about all
174-
// available options. Also it can happen that the ControlValueAccessor has an initial value
175-
// that should be used instead. Deferring the value change report to the next tick ensures
176-
// that the form control value is not being overwritten.
177-
Promise.resolve().then(() => this.selected = true);
178-
}
171+
// List options that are selected at initialization can't be reported properly to the form
172+
// control. This is because it takes some time until the selection-list knows about all
173+
// available options. Also it can happen that the ControlValueAccessor has an initial value
174+
// that should be used instead. Deferring the value change report to the next tick ensures
175+
// that the form control value is not being overwritten.
176+
const wasSelected = this._selected;
177+
178+
Promise.resolve().then(() => {
179+
if (this._selected || wasSelected) {
180+
this.selected = true;
181+
this._changeDetector.markForCheck();
182+
}
183+
});
179184
}
180185

181186
ngAfterContentInit() {

0 commit comments

Comments
 (0)