Skip to content

Commit

Permalink
fix(select): fix initial values with reactive forms (#2038)
Browse files Browse the repository at this point in the history
Closes #1973
  • Loading branch information
kara authored and tinayuangao committed Dec 1, 2016
1 parent 46ae3a2 commit 26eb7ce
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/demo-app/select/select-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class SelectDemo {
isRequired = false;
isDisabled = false;
currentDrink: string;
foodControl = new FormControl('');
foodControl = new FormControl('pizza-1');

foods = [
{value: 'steak-0', viewValue: 'Steak'},
Expand Down
21 changes: 21 additions & 0 deletions src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,29 @@ describe('MdSelect', () => {

beforeEach(() => {
fixture = TestBed.createComponent(BasicSelect);
});

it('should take an initial view value with reactive forms', () => {
fixture.componentInstance.control = new FormControl('pizza-1');
fixture.detectChanges();

const value = fixture.debugElement.query(By.css('.md-select-value'));
expect(value.nativeElement.textContent)
.toContain('Pizza', `Expected trigger to be populated by the control's initial value.`);

trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
trigger.click();
fixture.detectChanges();

const options =
overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;
expect(options[1].classList)
.toContain('md-selected',
`Expected option with the control's initial value to be selected.`);
});

beforeEach(() => {
fixture.detectChanges();
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
});

Expand Down
13 changes: 11 additions & 2 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ElementRef,
EventEmitter,
Input,
NgZone,
OnDestroy,
Optional,
Output,
Expand Down Expand Up @@ -133,7 +134,8 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
@Output() onClose = new EventEmitter();

constructor(private _element: ElementRef, private _renderer: Renderer,
@Optional() private _dir: Dir, @Optional() public _control: NgControl) {
@Optional() private _dir: Dir, @Optional() public _control: NgControl,
private _ngZone: NgZone) {
if (this._control) {
this._control.valueAccessor = this;
}
Expand Down Expand Up @@ -175,7 +177,14 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
* required to integrate with Angular's core forms API.
*/
writeValue(value: any): void {
if (!this.options) { return; }
if (!this.options) {
// In reactive forms, writeValue() will be called synchronously before
// the select's child options have been created. It's necessary to call
// writeValue() again after the options have been created to ensure any
// initial view value is set.
this._ngZone.onStable.first().subscribe(() => this.writeValue(value));
return;
}

this.options.forEach((option: MdOption) => {
if (option.value === value) {
Expand Down

0 comments on commit 26eb7ce

Please sign in to comment.