Skip to content

Commit

Permalink
fix(select): allow option with undefined or null value to clear selec…
Browse files Browse the repository at this point in the history
…tion

Allows for options, with a value of `null` or `undefined`, to clear the select. This is similar to the way the native select works.

Fixes angular#3110.
Fixes angular#2634.
  • Loading branch information
crisbeto committed May 22, 2017
1 parent d1b5e86 commit 7b47083
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 4 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 @@ -6,6 +6,8 @@

<md-select placeholder="Drink" [color]="drinksTheme" [(ngModel)]="currentDrink" [required]="drinksRequired" [disabled]="drinksDisabled"
[floatPlaceholder]="floatPlaceholder" #drinkControl="ngModel">
#drinkControl="ngModel">
<md-option>None</md-option>
<md-option *ngFor="let drink of drinks" [value]="drink.value" [disabled]="drink.disabled">
{{ drink.viewValue }}
</md-option>
Expand Down
1 change: 1 addition & 0 deletions src/demo-app/select/select-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class SelectDemo {
pokemonTheme = 'primary';

foods = [
{value: null, viewValue: 'None'},
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'}
Expand Down
95 changes: 94 additions & 1 deletion src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ describe('MdSelect', () => {
SelectEarlyAccessSibling,
BasicSelectInitiallyHidden,
BasicSelectNoPlaceholder,
BasicSelectWithTheming
BasicSelectWithTheming,
ResetValuesSelect
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -1995,6 +1996,72 @@ describe('MdSelect', () => {

});


describe('reset values', () => {
let fixture: ComponentFixture<ResetValuesSelect>;
let trigger: HTMLElement;
let placeholder: HTMLElement;
let options: NodeListOf<HTMLElement>;

beforeEach(() => {
fixture = TestBed.createComponent(ResetValuesSelect);
fixture.detectChanges();
trigger = fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement;
placeholder = fixture.debugElement.query(By.css('.mat-select-placeholder')).nativeElement;

trigger.click();
fixture.detectChanges();
options = overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;

options[0].click();
fixture.detectChanges();
});

it('should reset when an option with an undefined value is selected', () => {
options[4].click();
fixture.detectChanges();

expect(fixture.componentInstance.control.value).toBeUndefined();
expect(fixture.componentInstance.select.selected).toBeFalsy();
expect(placeholder.classList).not.toContain('mat-floating-placeholder');
expect(trigger.textContent).not.toContain('Undefined');
});

it('should reset when an option with a null value is selected', () => {
options[5].click();
fixture.detectChanges();

expect(fixture.componentInstance.control.value).toBeNull();
expect(fixture.componentInstance.select.selected).toBeFalsy();
expect(placeholder.classList).not.toContain('mat-floating-placeholder');
expect(trigger.textContent).not.toContain('Null');
});

it('should not reset when any other falsy option is selected', () => {
options[3].click();
fixture.detectChanges();

expect(fixture.componentInstance.control.value).toBe(false);
expect(fixture.componentInstance.select.selected).toBeTruthy();
expect(placeholder.classList).toContain('mat-floating-placeholder');
expect(trigger.textContent).toContain('Falsy');
});

it('should not consider the reset values as selected when resetting the form control', () => {
expect(placeholder.classList).toContain('mat-floating-placeholder');

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

expect(fixture.componentInstance.control.value).toBeNull();
expect(fixture.componentInstance.select.selected).toBeFalsy();
expect(placeholder.classList).not.toContain('mat-floating-placeholder');
expect(trigger.textContent).not.toContain('Null');
expect(trigger.textContent).not.toContain('Undefined');
});

});

});


Expand Down Expand Up @@ -2339,3 +2406,29 @@ class BasicSelectWithTheming {
@ViewChild(MdSelect) select: MdSelect;
theme: string;
}

@Component({
selector: 'reset-values-select',
template: `
<md-select placeholder="Food" [formControl]="control" [required]="isRequired">
<md-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</md-option>
</md-select>
`
})
class ResetValuesSelect {
foods: any[] = [
{ value: 'steak-0', viewValue: 'Steak' },
{ value: 'pizza-1', viewValue: 'Pizza' },
{ value: 'tacos-2', viewValue: 'Tacos' },
{ value: false, viewValue: 'Falsy' },
{ viewValue: 'Undefined' },
{ value: null, viewValue: 'Null' },
];
control = new FormControl();
isRequired: boolean;

@ViewChild(MdSelect) select: MdSelect;
@ViewChildren(MdOption) options: QueryList<MdOption>;
}
12 changes: 9 additions & 3 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
*/
private _selectValue(value: any): MdOption {
let optionsArray = this.options.toArray();
let correspondingOption = optionsArray.find(option => option.value === value);
let correspondingOption = optionsArray.find(option => option.value && option.value === value);

if (correspondingOption) {
correspondingOption.select();
Expand Down Expand Up @@ -632,8 +632,14 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
wasSelected ? option.deselect() : option.select();
this._sortValues();
} else {
this._clearSelection(option);
this._selectionModel.select(option);
if (option.value == null) {
this._clearSelection();
this._onChange(option.value);
this.change.emit(new MdSelectChange(this, option.value));
} else {
this._clearSelection(option);
this._selectionModel.select(option);
}
}

if (wasSelected !== this._selectionModel.isSelected(option)) {
Expand Down

0 comments on commit 7b47083

Please sign in to comment.