mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(autocomplete): placeholder should float while panel is open (#2730)
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
|||||||
Directive,
|
Directive,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
|
Host,
|
||||||
Input,
|
Input,
|
||||||
NgZone,
|
NgZone,
|
||||||
Optional,
|
Optional,
|
||||||
@@ -26,6 +27,7 @@ import 'rxjs/add/observable/of';
|
|||||||
import 'rxjs/add/observable/merge';
|
import 'rxjs/add/observable/merge';
|
||||||
import 'rxjs/add/operator/startWith';
|
import 'rxjs/add/operator/startWith';
|
||||||
import 'rxjs/add/operator/switchMap';
|
import 'rxjs/add/operator/switchMap';
|
||||||
|
import {MdInputContainer, FloatPlaceholderType} from '../input/input-container';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following style constants are necessary to save here in order
|
* The following style constants are necessary to save here in order
|
||||||
@@ -92,7 +94,8 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
|
|||||||
|
|
||||||
constructor(private _element: ElementRef, private _overlay: Overlay,
|
constructor(private _element: ElementRef, private _overlay: Overlay,
|
||||||
private _viewContainerRef: ViewContainerRef,
|
private _viewContainerRef: ViewContainerRef,
|
||||||
@Optional() private _dir: Dir, private _zone: NgZone) {}
|
@Optional() private _dir: Dir, private _zone: NgZone,
|
||||||
|
@Optional() @Host() private _inputContainer: MdInputContainer) {}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
this._keyManager = new ActiveDescendantKeyManager(this.autocomplete.options).withWrap();
|
this._keyManager = new ActiveDescendantKeyManager(this.autocomplete.options).withWrap();
|
||||||
@@ -123,6 +126,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._panelOpen = true;
|
this._panelOpen = true;
|
||||||
|
this._floatPlaceholder('always');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Closes the autocomplete suggestion panel. */
|
/** Closes the autocomplete suggestion panel. */
|
||||||
@@ -132,6 +136,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._panelOpen = false;
|
this._panelOpen = false;
|
||||||
|
this._floatPlaceholder('auto');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -214,6 +219,17 @@ export class MdAutocompleteTrigger implements AfterContentInit, ControlValueAcce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In "auto" mode, the placeholder will animate down as soon as focus is lost.
|
||||||
|
* This causes the value to jump when selecting an option with the mouse.
|
||||||
|
* This method manually floats the placeholder until the panel can be closed.
|
||||||
|
*/
|
||||||
|
private _floatPlaceholder(state: FloatPlaceholderType): void {
|
||||||
|
if (this._inputContainer) {
|
||||||
|
this._inputContainer.floatPlaceholder = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given that we are not actually focusing active options, we must manually adjust scroll
|
* Given that we are not actually focusing active options, we must manually adjust scroll
|
||||||
* to reveal options below the fold. First, we find the offset of the option from the top
|
* to reveal options below the fold. First, we find the offset of the option from the top
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {MdOption} from '../core/option/option';
|
|||||||
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
|
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
|
||||||
import {FakeViewportRuler} from '../core/overlay/position/fake-viewport-ruler';
|
import {FakeViewportRuler} from '../core/overlay/position/fake-viewport-ruler';
|
||||||
import {MdAutocomplete} from './autocomplete';
|
import {MdAutocomplete} from './autocomplete';
|
||||||
|
import {MdInputContainer} from '../input/input-container';
|
||||||
|
|
||||||
describe('MdAutocomplete', () => {
|
describe('MdAutocomplete', () => {
|
||||||
let overlayContainerElement: HTMLElement;
|
let overlayContainerElement: HTMLElement;
|
||||||
@@ -181,16 +181,36 @@ describe('MdAutocomplete', () => {
|
|||||||
.toEqual('', `Expected panel to close when options list is empty.`);
|
.toEqual('', `Expected panel to close when options list is empty.`);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should keep the label floating until the panel closes', () => {
|
||||||
|
fixture.componentInstance.trigger.openPanel();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
dispatchEvent('blur', input);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.componentInstance.inputContainer.floatPlaceholder)
|
||||||
|
.toEqual('always', 'Expected placeholder to keep floating on blur.');
|
||||||
|
|
||||||
|
const backdrop =
|
||||||
|
overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
|
||||||
|
backdrop.click();
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(fixture.componentInstance.inputContainer.floatPlaceholder)
|
||||||
|
.toEqual('auto', 'Expected placeholder to return to auto state after panel closes.');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have the correct text direction in RTL', () => {
|
it('should have the correct text direction in RTL', () => {
|
||||||
dir = 'rtl';
|
dir = 'rtl';
|
||||||
|
|
||||||
const fixture = TestBed.createComponent(SimpleAutocomplete);
|
const rtlFixture = TestBed.createComponent(SimpleAutocomplete);
|
||||||
fixture.detectChanges();
|
rtlFixture.detectChanges();
|
||||||
|
|
||||||
fixture.componentInstance.trigger.openPanel();
|
rtlFixture.componentInstance.trigger.openPanel();
|
||||||
fixture.detectChanges();
|
rtlFixture.detectChanges();
|
||||||
|
|
||||||
const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane');
|
const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane');
|
||||||
expect(overlayPane.getAttribute('dir')).toEqual('rtl');
|
expect(overlayPane.getAttribute('dir')).toEqual('rtl');
|
||||||
@@ -603,8 +623,8 @@ describe('MdAutocomplete', () => {
|
|||||||
// Expect option bottom minus the panel height (288 - 256 = 32)
|
// Expect option bottom minus the panel height (288 - 256 = 32)
|
||||||
expect(scrollContainer.scrollTop).toEqual(32, `Expected panel to reveal the sixth option.`);
|
expect(scrollContainer.scrollTop).toEqual(32, `Expected panel to reveal the sixth option.`);
|
||||||
});
|
});
|
||||||
}));
|
|
||||||
|
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('aria', () => {
|
describe('aria', () => {
|
||||||
@@ -793,6 +813,7 @@ class SimpleAutocomplete implements OnDestroy {
|
|||||||
|
|
||||||
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
|
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
|
||||||
@ViewChild(MdAutocomplete) panel: MdAutocomplete;
|
@ViewChild(MdAutocomplete) panel: MdAutocomplete;
|
||||||
|
@ViewChild(MdInputContainer) inputContainer: MdInputContainer;
|
||||||
@ViewChildren(MdOption) options: QueryList<MdOption>;
|
@ViewChildren(MdOption) options: QueryList<MdOption>;
|
||||||
|
|
||||||
states = [
|
states = [
|
||||||
|
|||||||
Reference in New Issue
Block a user