feat(input): option to imperatively float placeholder (#2585)

Closes #2466
This commit is contained in:
Paul Gschwendtner
2017-02-03 01:53:33 +01:00
committed by Kara
parent 4ed259a702
commit fb0cf8a277
6 changed files with 117 additions and 15 deletions
+10 -3
View File
@@ -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>
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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()">
+87 -4
View File
@@ -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>
+14 -4
View File
@@ -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;
+3 -1
View File
@@ -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.