Skip to content

Commit a00d8c8

Browse files
committed
fix(select): only animate placeholder when no selection
1 parent 26eb7ce commit a00d8c8

File tree

5 files changed

+46
-28
lines changed

5 files changed

+46
-28
lines changed

src/lib/select/select-animations.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import {
2020
* depending on the text direction of the application.
2121
*/
2222
export const transformPlaceholder: AnimationEntryMetadata = trigger('transformPlaceholder', [
23-
state('normal', style({
24-
transform: `translate3d(0, 0, 0) scale(1)`
25-
})),
2623
state('floating-ltr', style({
27-
transform: `translate3d(-2px, -22px, 0) scale(0.75)`
24+
top: '-22px',
25+
left: '-2px',
26+
transform: `scale(0.75)`
2827
})),
2928
state('floating-rtl', style({
30-
transform: `translate3d(2px, -22px, 0) scale(0.75)`
29+
top: '-22px',
30+
left: '2px',
31+
transform: `scale(0.75)`
3132
})),
3233
transition('* => *', animate(`400ms cubic-bezier(0.25, 0.8, 0.25, 1)`))
3334
]);

src/lib/select/select.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<div class="md-select-trigger" overlay-origin (click)="toggle()" #origin="overlayOrigin" #trigger>
2-
<span class="md-select-placeholder" [@transformPlaceholder]="_getPlaceholderState()"> {{ placeholder }} </span>
2+
<span class="md-select-placeholder" [class.md-floating-placeholder]="this._selected"
3+
[@transformPlaceholder]="_placeholderState"> {{ placeholder }} </span>
34
<span class="md-select-value" *ngIf="selected"> {{ selected?.viewValue }} </span>
45
<span class="md-select-arrow"></span>
56
</div>

src/lib/select/select.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,22 @@ md-select {
3030
}
3131

3232
.md-select-placeholder {
33+
position: relative;
3334
padding: 0 2px;
3435
transform-origin: left top;
3536

37+
&.md-floating-placeholder {
38+
top: -22px;
39+
left: -2px;
40+
transform: scale(0.75);
41+
}
42+
3643
[dir='rtl'] & {
3744
transform-origin: right top;
45+
46+
&.md-floating-placeholder {
47+
left: 2px;
48+
}
3849
}
3950

4051
// TODO: Double-check accessibility of this style

src/lib/select/select.spec.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,38 +456,43 @@ describe('MdSelect', () => {
456456
trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
457457
});
458458

459-
it('should float the placeholder when the panel is open', () => {
460-
expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('normal');
459+
it('should float the placeholder when the panel is open and unselected', () => {
460+
expect(fixture.componentInstance.select._placeholderState)
461+
.toEqual('', 'Expected placeholder to initially have a normal position.');
461462

462463
trigger.click();
463464
fixture.detectChanges();
464-
expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-ltr');
465+
expect(fixture.componentInstance.select._placeholderState)
466+
.toEqual('floating-ltr', 'Expected placeholder to animate up to floating position.');
465467

466468
const backdrop =
467469
overlayContainerElement.querySelector('.md-overlay-backdrop') as HTMLElement;
468470
backdrop.click();
469471
fixture.detectChanges();
470472

471-
expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('normal');
473+
expect(fixture.componentInstance.select._placeholderState)
474+
.toEqual('', 'Expected placeholder to animate back down to normal position.');
472475
});
473476

474-
it('should float the placeholder when there is a selection', () => {
475-
trigger.click();
477+
it('should float the placeholder without animation when value is set', () => {
478+
fixture.componentInstance.control.setValue('pizza-1');
476479
fixture.detectChanges();
477480

478-
const option = overlayContainerElement.querySelector('md-option') as HTMLElement;
479-
option.click();
480-
fixture.detectChanges();
481+
const placeholderEl =
482+
fixture.debugElement.query(By.css('.md-select-placeholder')).nativeElement;
481483

482-
expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-ltr');
484+
expect(placeholderEl.classList)
485+
.toContain('md-floating-placeholder', 'Expected placeholder to display as floating.');
486+
expect(fixture.componentInstance.select._placeholderState)
487+
.toEqual('', 'Expected animation state to be empty to avoid animation.');
483488
});
484489

485490
it('should use the floating-rtl state when the dir is rtl', () => {
486491
dir.value = 'rtl';
487492

488493
trigger.click();
489494
fixture.detectChanges();
490-
expect(fixture.componentInstance.select._getPlaceholderState()).toEqual('floating-rtl');
495+
expect(fixture.componentInstance.select._placeholderState).toEqual('floating-rtl');
491496
});
492497

493498
it('should use the ltr panel state when the dir is ltr', () => {

src/lib/select/select.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
7171
/** Whether the select is disabled. */
7272
private _disabled: boolean = false;
7373

74+
/** The animation state of the placeholder. */
75+
_placeholderState = '';
76+
7477
/** Manages keyboard events for options in the panel. */
7578
_keyManager: ListKeyManager;
7679

@@ -163,12 +166,16 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
163166
if (this.disabled) {
164167
return;
165168
}
169+
this._placeholderState = this._isRtl() ? 'floating-rtl' : 'floating-ltr';
166170
this._panelOpen = true;
167171
}
168172

169173
/** Closes the overlay panel and focuses the host element. */
170174
close(): void {
171175
this._panelOpen = false;
176+
if (!this._selected) {
177+
this._placeholderState = '';
178+
}
172179
this._focusHost();
173180
}
174181

@@ -182,7 +189,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
182189
// the select's child options have been created. It's necessary to call
183190
// writeValue() again after the options have been created to ensure any
184191
// initial view value is set.
185-
this._ngZone.onStable.first().subscribe(() => this.writeValue(value));
192+
this._ngZone.onMicrotaskEmpty.first().subscribe(() => this.writeValue(value));
186193
return;
187194
}
188195

@@ -240,15 +247,6 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
240247
return this.trigger.nativeElement.getBoundingClientRect().width;
241248
}
242249

243-
/** The animation state of the placeholder. */
244-
_getPlaceholderState(): string {
245-
if (this.panelOpen || this.selected) {
246-
return this._isRtl() ? 'floating-rtl' : 'floating-ltr';
247-
} else {
248-
return 'normal';
249-
}
250-
}
251-
252250
/** The animation state of the overlay panel. */
253251
_getPanelState(): string {
254252
return this._isRtl() ? `${this._transformOrigin}-rtl` : `${this._transformOrigin}-ltr`;
@@ -340,7 +338,9 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
340338
private _onSelect(option: MdOption): void {
341339
this._selected = option;
342340
this._updateOptions();
343-
this.close();
341+
if (this.panelOpen) {
342+
this.close();
343+
}
344344
}
345345

346346
/** Deselect each option that doesn't match the current selection. */

0 commit comments

Comments
 (0)