diff --git a/src/lib/select/select-animations.ts b/src/lib/select/select-animations.ts
index 238341138c39..a2607dc34c21 100644
--- a/src/lib/select/select-animations.ts
+++ b/src/lib/select/select-animations.ts
@@ -20,14 +20,15 @@ import {
* depending on the text direction of the application.
*/
export const transformPlaceholder: AnimationEntryMetadata = trigger('transformPlaceholder', [
- state('normal', style({
- transform: `translate3d(0, 0, 0) scale(1)`
- })),
state('floating-ltr', style({
- transform: `translate3d(-2px, -22px, 0) scale(0.75)`
+ top: '-22px',
+ left: '-2px',
+ transform: `scale(0.75)`
})),
state('floating-rtl', style({
- transform: `translate3d(2px, -22px, 0) scale(0.75)`
+ top: '-22px',
+ left: '2px',
+ transform: `scale(0.75)`
})),
transition('* => *', animate(`400ms cubic-bezier(0.25, 0.8, 0.25, 1)`))
]);
diff --git a/src/lib/select/select.html b/src/lib/select/select.html
index f95dc6b1c6e8..b5efc703e8b5 100644
--- a/src/lib/select/select.html
+++ b/src/lib/select/select.html
@@ -1,5 +1,6 @@
- {{ placeholder }}
+ {{ placeholder }}
{{ selected?.viewValue }}
diff --git a/src/lib/select/select.scss b/src/lib/select/select.scss
index 60f1a1e49e68..2dbe50a743d0 100644
--- a/src/lib/select/select.scss
+++ b/src/lib/select/select.scss
@@ -30,11 +30,22 @@ md-select {
}
.md-select-placeholder {
+ position: relative;
padding: 0 2px;
transform-origin: left top;
+ &.md-floating-placeholder {
+ top: -22px;
+ left: -2px;
+ transform: scale(0.75);
+ }
+
[dir='rtl'] & {
transform-origin: right top;
+
+ &.md-floating-placeholder {
+ left: 2px;
+ }
}
// TODO: Double-check accessibility of this style
diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts
index 1c0dddabc878..da8742635899 100644
--- a/src/lib/select/select.spec.ts
+++ b/src/lib/select/select.spec.ts
@@ -456,30 +456,35 @@ describe('MdSelect', () => {
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
});
- it('should float the placeholder when the panel is open', () => {
- expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('normal');
+ it('should float the placeholder when the panel is open and unselected', () => {
+ expect(fixture.componentInstance.select._placeholderState)
+ .toEqual('', 'Expected placeholder to initially have a normal position.');
trigger.click();
fixture.detectChanges();
- expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-ltr');
+ expect(fixture.componentInstance.select._placeholderState)
+ .toEqual('floating-ltr', 'Expected placeholder to animate up to floating position.');
const backdrop =
overlayContainerElement.querySelector('.md-overlay-backdrop') as HTMLElement;
backdrop.click();
fixture.detectChanges();
- expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('normal');
+ expect(fixture.componentInstance.select._placeholderState)
+ .toEqual('', 'Expected placeholder to animate back down to normal position.');
});
- it('should float the placeholder when there is a selection', () => {
- trigger.click();
+ it('should float the placeholder without animation when value is set', () => {
+ fixture.componentInstance.control.setValue('pizza-1');
fixture.detectChanges();
- const option = overlayContainerElement.querySelector('md-option') as HTMLElement;
- option.click();
- fixture.detectChanges();
+ const placeholderEl =
+ fixture.debugElement.query(By.css('.md-select-placeholder')).nativeElement;
- expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-ltr');
+ expect(placeholderEl.classList)
+ .toContain('md-floating-placeholder', 'Expected placeholder to display as floating.');
+ expect(fixture.componentInstance.select._placeholderState)
+ .toEqual('', 'Expected animation state to be empty to avoid animation.');
});
it('should use the floating-rtl state when the dir is rtl', () => {
@@ -487,7 +492,7 @@ describe('MdSelect', () => {
trigger.click();
fixture.detectChanges();
- expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-rtl');
+ expect(fixture.componentInstance.select._placeholderState).toEqual('floating-rtl');
});
it('should use the ltr panel state when the dir is ltr', () => {
diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts
index 90af646afe68..60757fac126b 100644
--- a/src/lib/select/select.ts
+++ b/src/lib/select/select.ts
@@ -71,6 +71,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
/** Whether the select is disabled. */
private _disabled: boolean = false;
+ /** The animation state of the placeholder. */
+ _placeholderState = '';
+
/** Manages keyboard events for options in the panel. */
_keyManager: ListKeyManager;
@@ -163,12 +166,16 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
if (this.disabled) {
return;
}
+ this._placeholderState = this._isRtl() ? 'floating-rtl' : 'floating-ltr';
this._panelOpen = true;
}
/** Closes the overlay panel and focuses the host element. */
close(): void {
this._panelOpen = false;
+ if (!this._selected) {
+ this._placeholderState = '';
+ }
this._focusHost();
}
@@ -182,7 +189,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
// 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));
+ this._ngZone.onMicrotaskEmpty.first().subscribe(() => this.writeValue(value));
return;
}
@@ -240,15 +247,6 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
return this.trigger.nativeElement.getBoundingClientRect().width;
}
- /** The animation state of the placeholder. */
- _getPlaceholderState(): string {
- if (this.panelOpen || this.selected) {
- return this._isRtl() ? 'floating-rtl' : 'floating-ltr';
- } else {
- return 'normal';
- }
- }
-
/** The animation state of the overlay panel. */
_getPanelState(): string {
return this._isRtl() ? `${this._transformOrigin}-rtl` : `${this._transformOrigin}-ltr`;
@@ -340,7 +338,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
private _onSelect(option: MdOption): void {
this._selected = option;
this._updateOptions();
- this.close();
+ if (this.panelOpen) {
+ this.close();
+ }
}
/** Deselect each option that doesn't match the current selection. */