mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(input): option to imperatively float placeholder (#2585)
Closes #2466
This commit is contained in:
@@ -180,9 +180,16 @@
|
||||
</md-input-container>
|
||||
</p>
|
||||
<p>
|
||||
<md-checkbox [(ngModel)]="floatingLabel"> Check to make floating label:</md-checkbox>
|
||||
<md-input-container [floatingPlaceholder]="floatingLabel">
|
||||
<input mdInput [placeholder]="floatingLabel ? 'Floating label' : 'Not floating label'">
|
||||
<md-button-toggle-group [(ngModel)]="floatingLabel">
|
||||
<md-button-toggle value="auto">Auto Float</md-button-toggle>
|
||||
<md-button-toggle value="always">Always Float</md-button-toggle>
|
||||
<md-button-toggle value="never">Never Float</md-button-toggle>
|
||||
</md-button-toggle-group>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<md-input-container [floatPlaceholder]="floatingLabel">
|
||||
<input mdInput placeholder="Placeholder">
|
||||
</md-input-container>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ let max = 5;
|
||||
styleUrls: ['input-container-demo.css'],
|
||||
})
|
||||
export class InputContainerDemo {
|
||||
floatingLabel: string = 'auto';
|
||||
dividerColor: boolean;
|
||||
requiredField: boolean;
|
||||
floatingLabel: boolean;
|
||||
ctrlDisabled = false;
|
||||
|
||||
name: string;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
<label class="md-input-placeholder"
|
||||
[attr.for]="_mdInputChild.id"
|
||||
[class.md-empty]="_mdInputChild.empty"
|
||||
[class.md-empty]="_mdInputChild.empty && !_shouldAlwaysFloat"
|
||||
[class.md-focused]="_mdInputChild.focused"
|
||||
[class.md-float]="floatingPlaceholder"
|
||||
[class.md-float]="_canPlaceholderFloat"
|
||||
[class.md-accent]="dividerColor == 'accent'"
|
||||
[class.md-warn]="dividerColor == 'warn'"
|
||||
*ngIf="_hasPlaceholder()">
|
||||
|
||||
@@ -48,7 +48,8 @@ describe('MdInputContainer', function () {
|
||||
MdInputContainerWithStaticPlaceholder,
|
||||
MdInputContainerMissingMdInputTestController,
|
||||
MdInputContainerMultipleHintTestController,
|
||||
MdInputContainerMultipleHintMixedTestController
|
||||
MdInputContainerMultipleHintMixedTestController,
|
||||
MdInputContainerWithDynamicPlaceholder
|
||||
],
|
||||
});
|
||||
|
||||
@@ -61,8 +62,8 @@ describe('MdInputContainer', function () {
|
||||
|
||||
let inputContainer = fixture.debugElement.query(By.directive(MdInputContainer))
|
||||
.componentInstance as MdInputContainer;
|
||||
expect(inputContainer.floatingPlaceholder).toBe(true,
|
||||
'Expected MdInputContainer to default to having floating placeholders turned on');
|
||||
expect(inputContainer.floatPlaceholder).toBe('auto',
|
||||
'Expected MdInputContainer to set floatingLabel to auto by default.');
|
||||
});
|
||||
|
||||
it('should not be treated as empty if type is date',
|
||||
@@ -477,6 +478,78 @@ describe('MdInputContainer', function () {
|
||||
|
||||
expect(ariaValue).toBe(`${hintLabel.getAttribute('id')} ${endLabel.getAttribute('id')}`);
|
||||
});
|
||||
|
||||
it('should float when floatPlaceholder is set to default and text is entered', () => {
|
||||
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);
|
||||
fixture.detectChanges();
|
||||
|
||||
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
let labelEl = fixture.debugElement.query(By.css('label')).nativeElement;
|
||||
|
||||
expect(labelEl.classList).not.toContain('md-empty');
|
||||
expect(labelEl.classList).toContain('md-float');
|
||||
|
||||
fixture.componentInstance.shouldFloat = 'auto';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelEl.classList).toContain('md-empty');
|
||||
expect(labelEl.classList).toContain('md-float');
|
||||
|
||||
// Update the value of the input.
|
||||
inputEl.value = 'Text';
|
||||
|
||||
// Fake behavior of the `(input)` event which should trigger a change detection.
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelEl.classList).not.toContain('md-empty');
|
||||
expect(labelEl.classList).toContain('md-float');
|
||||
});
|
||||
|
||||
it('should always float the placeholder when floatPlaceholder is set to true', () => {
|
||||
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);
|
||||
fixture.detectChanges();
|
||||
|
||||
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
let labelEl = fixture.debugElement.query(By.css('label')).nativeElement;
|
||||
|
||||
expect(labelEl.classList).not.toContain('md-empty');
|
||||
expect(labelEl.classList).toContain('md-float');
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
// Update the value of the input.
|
||||
inputEl.value = 'Text';
|
||||
|
||||
// Fake behavior of the `(input)` event which should trigger a change detection.
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelEl.classList).not.toContain('md-empty');
|
||||
expect(labelEl.classList).toContain('md-float');
|
||||
});
|
||||
|
||||
|
||||
it('should never float the placeholder when floatPlaceholder is set to false', () => {
|
||||
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);
|
||||
|
||||
fixture.componentInstance.shouldFloat = 'never';
|
||||
fixture.detectChanges();
|
||||
|
||||
let inputEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
let labelEl = fixture.debugElement.query(By.css('label')).nativeElement;
|
||||
|
||||
expect(labelEl.classList).toContain('md-empty');
|
||||
expect(labelEl.classList).not.toContain('md-float');
|
||||
|
||||
// Update the value of the input.
|
||||
inputEl.value = 'Text';
|
||||
|
||||
// Fake behavior of the `(input)` event which should trigger a change detection.
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(labelEl.classList).not.toContain('md-empty');
|
||||
expect(labelEl.classList).not.toContain('md-float');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@Component({
|
||||
@@ -668,13 +741,23 @@ class MdInputContainerWithValueBinding {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container [floatingPlaceholder]="false">
|
||||
<md-input-container floatPlaceholder="never">
|
||||
<input mdInput placeholder="Label">
|
||||
</md-input-container>
|
||||
`
|
||||
})
|
||||
class MdInputContainerWithStaticPlaceholder {}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container [floatPlaceholder]="shouldFloat">
|
||||
<input mdInput placeholder="Label">
|
||||
</md-input-container>`
|
||||
})
|
||||
class MdInputContainerWithDynamicPlaceholder {
|
||||
shouldFloat: string = 'always';
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container>
|
||||
|
||||
@@ -38,6 +38,8 @@ const MD_INPUT_INVALID_TYPES = [
|
||||
'submit'
|
||||
];
|
||||
|
||||
/** Type for the available floatPlaceholder values. */
|
||||
export type FloatPlaceholderType = 'always' | 'never' | 'auto';
|
||||
|
||||
let nextUniqueId = 0;
|
||||
|
||||
@@ -253,6 +255,12 @@ export class MdInputContainer implements AfterContentInit {
|
||||
/** Color of the input divider, based on the theme. */
|
||||
@Input() dividerColor: 'primary' | 'accent' | 'warn' = 'primary';
|
||||
|
||||
/** Whether the floating label should always float or not. */
|
||||
get _shouldAlwaysFloat() { return this._floatPlaceholder === 'always'; };
|
||||
|
||||
/** Whether the placeholder can float or not. */
|
||||
get _canPlaceholderFloat() { return this._floatPlaceholder !== 'never'; }
|
||||
|
||||
/** Text for the input hint. */
|
||||
@Input()
|
||||
get hintLabel() { return this._hintLabel; }
|
||||
@@ -265,11 +273,13 @@ export class MdInputContainer implements AfterContentInit {
|
||||
// Unique id for the hint label.
|
||||
_hintLabelId: string = `md-input-hint-${nextUniqueId++}`;
|
||||
|
||||
/** Text or the floating placeholder. */
|
||||
/** Whether the placeholder should always float, never float or float as the user types. */
|
||||
@Input()
|
||||
get floatingPlaceholder(): boolean { return this._floatingPlaceholder; }
|
||||
set floatingPlaceholder(value) { this._floatingPlaceholder = coerceBooleanProperty(value); }
|
||||
private _floatingPlaceholder: boolean = true;
|
||||
get floatPlaceholder() { return this._floatPlaceholder; }
|
||||
set floatPlaceholder(value: FloatPlaceholderType) {
|
||||
this._floatPlaceholder = value || 'auto';
|
||||
}
|
||||
private _floatPlaceholder: FloatPlaceholderType = 'auto';
|
||||
|
||||
@ContentChild(MdInputDirective) _mdInputChild: MdInputDirective;
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@ be used with `md-input-container`:
|
||||
A placeholder is an indicative text displayed in the input zone when the input does not contain
|
||||
text. When text is present, the indicative text will float above this input zone.
|
||||
|
||||
The `floatingPlaceholder` attribute of `md-input-container` can be set to `false` to hide the
|
||||
The `floatPlaceholder` attribute of `md-input-container` can be set to `never` to hide the
|
||||
indicative text instead when text is present in the input.
|
||||
|
||||
When setting `floatPlaceholder` to `always` the floating label will always show above the input.
|
||||
|
||||
A placeholder for the input can be specified in one of two ways: either using the `placeholder`
|
||||
attribute on the `input` or `textarea`, or using an `md-placeholder` element in the
|
||||
`md-input-container`. Using both will raise an error.
|
||||
|
||||
Reference in New Issue
Block a user