Skip to content

Commit

Permalink
fix(select): clear select if no option matches value (#2110)
Browse files Browse the repository at this point in the history
Closes #2109
  • Loading branch information
kara authored and jelbourn committed Dec 16, 2016
1 parent cac72aa commit 2855cc3
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 16 deletions.
2 changes: 2 additions & 0 deletions src/demo-app/select/select-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<p> Status: {{ foodControl.status }} </p>
<button md-button (click)="foodControl.setValue('pizza-1')">SET VALUE</button>
<button md-button (click)="toggleDisabled()">TOGGLE DISABLED</button>
<button md-button (click)="foodControl.reset()">RESET</button>
</md-card>
</div>

Expand All @@ -30,6 +31,7 @@
<button md-button (click)="currentDrink='sprite-1'">SET VALUE</button>
<button md-button (click)="isRequired=!isRequired">TOGGLE REQUIRED</button>
<button md-button (click)="isDisabled=!isDisabled">TOGGLE DISABLED</button>
<button md-button (click)="drinkControl.reset()">RESET</button>
</md-card>

</div>
Expand Down
65 changes: 54 additions & 11 deletions src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,19 +193,19 @@ describe('MdSelect', () => {
});

it('should focus the selected option if an option is selected', async(() => {
trigger.click();
fixture.detectChanges();

const options =
overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;
options[1].click();
fixture.detectChanges();
// must wait for initial writeValue promise to finish
fixture.whenStable().then(() => {
fixture.componentInstance.control.setValue('pizza-1');
fixture.detectChanges();

trigger.click();
fixture.detectChanges();
trigger.click();
fixture.detectChanges();

fixture.whenStable().then(() => {
expect(fixture.componentInstance.select._keyManager.focusedItemIndex).toEqual(1);
// must wait for animation to finish
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.componentInstance.select._keyManager.focusedItemIndex).toEqual(1);
});
});
}));

Expand Down Expand Up @@ -307,6 +307,49 @@ describe('MdSelect', () => {
.toEqual('steak-0', `Expected control's value to be set to the new option.`);
});

it('should clear the selection when a nonexistent option value is selected', () => {
fixture.componentInstance.control.setValue('pizza-1');
fixture.detectChanges();

fixture.componentInstance.control.setValue('gibberish');
fixture.detectChanges();

const value = fixture.debugElement.query(By.css('.md-select-value'));
expect(value).toBe(null, `Expected trigger to be cleared when option value is not found.`);
expect(trigger.textContent)
.not.toContain('Pizza', `Expected trigger to be cleared when option value is not found.`);

trigger.click();
fixture.detectChanges();

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


it('should clear the selection when the control is reset', () => {
fixture.componentInstance.control.setValue('pizza-1');
fixture.detectChanges();

fixture.componentInstance.control.reset();
fixture.detectChanges();

const value = fixture.debugElement.query(By.css('.md-select-value'));
expect(value).toBe(null, `Expected trigger to be cleared when option value is not found.`);
expect(trigger.textContent)
.not.toContain('Pizza', `Expected trigger to be cleared when option value is not found.`);

trigger.click();
fixture.detectChanges();

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

it('should set the control to touched when the select is touched', () => {
expect(fixture.componentInstance.control.touched)
.toEqual(false, `Expected the control to start off as untouched.`);
Expand Down
31 changes: 26 additions & 5 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
return;
}

this.options.forEach((option: MdOption) => {
if (option.value === value) {
option.select();
}
});
this._setSelectionByValue(value);
}

/**
Expand Down Expand Up @@ -378,6 +374,30 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
scrollContainer.scrollTop = this._scrollTop;
}

/**
* Sets the selected option based on a value. If no option can be
* found with the designated value, the select trigger is cleared.
*/
private _setSelectionByValue(value: any): void {
const options = this.options.toArray();

for (let i = 0; i < this.options.length; i++) {
if (options[i].value === value) {
options[i].select();
return;
}
}

// Clear selection if no item was selected.
this._clearSelection();
}

/** Clears the select trigger and deselects every option in the list. */
private _clearSelection(): void {
this._selected = null;
this._updateOptions();
}

private _getTriggerRect(): ClientRect {
return this.trigger.nativeElement.getBoundingClientRect();
}
Expand Down Expand Up @@ -426,6 +446,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
this._selected = option;
this._updateOptions();
this._setValueWidth();
this._placeholderState = '';
if (this.panelOpen) {
this.close();
}
Expand Down

0 comments on commit 2855cc3

Please sign in to comment.