Skip to content

Commit 26eb7ce

Browse files
karatinayuangao
authored andcommitted
fix(select): fix initial values with reactive forms (#2038)
Closes #1973
1 parent 46ae3a2 commit 26eb7ce

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

src/demo-app/select/select-demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class SelectDemo {
1111
isRequired = false;
1212
isDisabled = false;
1313
currentDrink: string;
14-
foodControl = new FormControl('');
14+
foodControl = new FormControl('pizza-1');
1515

1616
foods = [
1717
{value: 'steak-0', viewValue: 'Steak'},

src/lib/select/select.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,29 @@ describe('MdSelect', () => {
244244

245245
beforeEach(() => {
246246
fixture = TestBed.createComponent(BasicSelect);
247+
});
248+
249+
it('should take an initial view value with reactive forms', () => {
250+
fixture.componentInstance.control = new FormControl('pizza-1');
251+
fixture.detectChanges();
252+
253+
const value = fixture.debugElement.query(By.css('.md-select-value'));
254+
expect(value.nativeElement.textContent)
255+
.toContain('Pizza', `Expected trigger to be populated by the control's initial value.`);
256+
257+
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
258+
trigger.click();
247259
fixture.detectChanges();
248260

261+
const options =
262+
overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;
263+
expect(options[1].classList)
264+
.toContain('md-selected',
265+
`Expected option with the control's initial value to be selected.`);
266+
});
267+
268+
beforeEach(() => {
269+
fixture.detectChanges();
249270
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
250271
});
251272

src/lib/select/select.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ElementRef,
66
EventEmitter,
77
Input,
8+
NgZone,
89
OnDestroy,
910
Optional,
1011
Output,
@@ -133,7 +134,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
133134
@Output() onClose = new EventEmitter();
134135

135136
constructor(private _element: ElementRef, private _renderer: Renderer,
136-
@Optional() private _dir: Dir, @Optional() public _control: NgControl) {
137+
@Optional() private _dir: Dir, @Optional() public _control: NgControl,
138+
private _ngZone: NgZone) {
137139
if (this._control) {
138140
this._control.valueAccessor = this;
139141
}
@@ -175,7 +177,14 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
175177
* required to integrate with Angular's core forms API.
176178
*/
177179
writeValue(value: any): void {
178-
if (!this.options) { return; }
180+
if (!this.options) {
181+
// In reactive forms, writeValue() will be called synchronously before
182+
// the select's child options have been created. It's necessary to call
183+
// writeValue() again after the options have been created to ensure any
184+
// initial view value is set.
185+
this._ngZone.onStable.first().subscribe(() => this.writeValue(value));
186+
return;
187+
}
179188

180189
this.options.forEach((option: MdOption) => {
181190
if (option.value === value) {

0 commit comments

Comments
 (0)