Skip to content

Commit

Permalink
fix(selection-list): preselected options not being added to the model…
Browse files Browse the repository at this point in the history
… value (#9116)

Fixes preselected list options not being added to the model due to:
* The `Promise.resolve` inside the `ngOnInit` not actually doing anything due to a missing `.then`.
* The option not being added to the selection model when the value is emitted, which means that it won't be a part of the model.
  • Loading branch information
crisbeto authored and jelbourn committed Jan 8, 2018
1 parent f64a857 commit 2235239
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
56 changes: 55 additions & 1 deletion src/lib/list/selection-list.spec.ts
Expand Up @@ -556,7 +556,9 @@ describe('MatSelectionList with forms', () => {
imports: [MatListModule, FormsModule, ReactiveFormsModule],
declarations: [
SelectionListWithModel,
SelectionListWithFormControl
SelectionListWithFormControl,
SelectionListWithPreselectedOption,
SelectionListWithPreselectedOptionAndModel
]
});

Expand Down Expand Up @@ -719,6 +721,34 @@ describe('MatSelectionList with forms', () => {
expect(listOptions[2].selected).toBe(true, 'Expected third option to be selected.');
});
});

describe('preselected values', () => {
it('should add preselected options to the model value', fakeAsync(() => {
const fixture = TestBed.createComponent(SelectionListWithPreselectedOption);
const listOptions = fixture.debugElement.queryAll(By.directive(MatListOption))
.map(optionDebugEl => optionDebugEl.componentInstance);

fixture.detectChanges();
tick();

expect(listOptions[1].selected).toBe(true);
expect(fixture.componentInstance.selectedOptions).toEqual(['opt2']);
}));

it('should handle preselected option both through the model and the view', fakeAsync(() => {
const fixture = TestBed.createComponent(SelectionListWithPreselectedOptionAndModel);
const listOptions = fixture.debugElement.queryAll(By.directive(MatListOption))
.map(optionDebugEl => optionDebugEl.componentInstance);

fixture.detectChanges();
tick();

expect(listOptions[0].selected).toBe(true);
expect(listOptions[1].selected).toBe(true);
expect(fixture.componentInstance.selectedOptions).toEqual(['opt1', 'opt2']);
}));

});
});


Expand Down Expand Up @@ -842,3 +872,27 @@ class SelectionListWithModel {
class SelectionListWithFormControl {
formControl = new FormControl();
}


@Component({
template: `
<mat-selection-list [(ngModel)]="selectedOptions">
<mat-list-option value="opt1">Option 1</mat-list-option>
<mat-list-option value="opt2" selected>Option 2</mat-list-option>
</mat-selection-list>`
})
class SelectionListWithPreselectedOption {
selectedOptions: string[];
}


@Component({
template: `
<mat-selection-list [(ngModel)]="selectedOptions">
<mat-list-option value="opt1">Option 1</mat-list-option>
<mat-list-option value="opt2" selected>Option 2</mat-list-option>
</mat-selection-list>`
})
class SelectionListWithPreselectedOptionAndModel {
selectedOptions = ['opt1'];
}
4 changes: 2 additions & 2 deletions src/lib/list/selection-list.ts
Expand Up @@ -163,13 +163,13 @@ export class MatListOption extends _MatListOptionMixinBase
}

ngOnInit() {
if (this.selected) {
if (this._selected) {
// List options that are selected at initialization can't be reported properly to the form
// control. This is because it takes some time until the selection-list knows about all
// available options. Also it can happen that the ControlValueAccessor has an initial value
// that should be used instead. Deferring the value change report to the next tick ensures
// that the form control value is not being overwritten.
Promise.resolve(() => this.selected && this.selectionList._reportValueChange());
Promise.resolve().then(() => this.selected = true);
}
}

Expand Down

0 comments on commit 2235239

Please sign in to comment.