diff --git a/src/demo-app/input/input-container-demo.html b/src/demo-app/input/input-container-demo.html index 3c9bfa74e210..9cfb12ed6fd5 100644 --- a/src/demo-app/input/input-container-demo.html +++ b/src/demo-app/input/input-container-demo.html @@ -180,10 +180,16 @@

Textarea

- Toggle Floating Label - + + Auto Float + Always Float + Never Float + +

+ +

- +

diff --git a/src/demo-app/input/input-container-demo.ts b/src/demo-app/input/input-container-demo.ts index 9c702e23ed3e..fad9c6b7058e 100644 --- a/src/demo-app/input/input-container-demo.ts +++ b/src/demo-app/input/input-container-demo.ts @@ -11,9 +11,9 @@ let max = 5; styleUrls: ['input-demo.css'], }) export class InputContainerDemo { + floatingLabel: string = 'auto'; dividerColor: boolean; requiredField: boolean; - floatingLabel: boolean; ctrlDisabled = false; name: string; diff --git a/src/lib/input/OVERVIEW.md b/src/lib/input/OVERVIEW.md index 680cb524ed93..c2d12d32c1ad 100644 --- a/src/lib/input/OVERVIEW.md +++ b/src/lib/input/OVERVIEW.md @@ -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 `floatingPlaceholder` 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 `floatingPlaceholder` 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. diff --git a/src/lib/input/input-container-errors.ts b/src/lib/input/input-container-errors.ts index 90a9337b2a65..00864cdfec94 100644 --- a/src/lib/input/input-container-errors.ts +++ b/src/lib/input/input-container-errors.ts @@ -28,3 +28,9 @@ export class MdInputContainerMissingMdInputError extends MdError { 'to the native input or textarea element?'); } } + +export class MdInputContainerFloatingPlaceholderInvalidError extends MdError { + constructor(value: string) { + super(`The value "${value}" for the floatingPlaceholder input is not valid.`); + } +} diff --git a/src/lib/input/input-container.html b/src/lib/input/input-container.html index 677be89f478a..7a88e046283a 100644 --- a/src/lib/input/input-container.html +++ b/src/lib/input/input-container.html @@ -9,7 +9,7 @@ [attr.for]="_mdInputChild.id" [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()"> diff --git a/src/lib/input/input-container.spec.ts b/src/lib/input/input-container.spec.ts index f0cafea0975b..072e093fb384 100644 --- a/src/lib/input/input-container.spec.ts +++ b/src/lib/input/input-container.spec.ts @@ -60,8 +60,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.floatingPlaceholder).toBe('auto', + 'Expected MdInputContainer to set floatingLabel to auto by default.'); }); it('should not be treated as empty if type is date', @@ -410,20 +410,20 @@ describe('MdInputContainer', function () { let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder); fixture.detectChanges(); - let inputEl = fixture.debugElement.query(By.css('input')); + 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 = null; + 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.nativeElement.value = 'Text'; + inputEl.value = 'Text'; // Fake behavior of the `(input)` event which should trigger a change detection. fixture.detectChanges(); @@ -436,7 +436,7 @@ describe('MdInputContainer', function () { let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder); fixture.detectChanges(); - let inputEl = fixture.debugElement.query(By.css('input')); + 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'); @@ -445,7 +445,7 @@ describe('MdInputContainer', function () { fixture.detectChanges(); // Update the value of the input. - inputEl.nativeElement.value = 'Text'; + inputEl.value = 'Text'; // Fake behavior of the `(input)` event which should trigger a change detection. fixture.detectChanges(); @@ -458,17 +458,17 @@ describe('MdInputContainer', function () { it('should never float the placeholder when floatingPlaceholder is set to false', () => { let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder); - fixture.componentInstance.shouldFloat = false; + fixture.componentInstance.shouldFloat = 'never'; fixture.detectChanges(); - let inputEl = fixture.debugElement.query(By.css('input')); + 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.nativeElement.value = 'Text'; + inputEl.value = 'Text'; // Fake behavior of the `(input)` event which should trigger a change detection. fixture.detectChanges(); @@ -646,7 +646,7 @@ class MdInputContainerWithValueBinding { @Component({ template: ` - + ` @@ -660,7 +660,7 @@ class MdInputContainerWithStaticPlaceholder {} ` }) class MdInputContainerWithDynamicPlaceholder { - shouldFloat: boolean = true; + shouldFloat: string = 'always'; } @Component({ diff --git a/src/lib/input/input-container.ts b/src/lib/input/input-container.ts index e22789d8f544..abdb1a82f5a7 100644 --- a/src/lib/input/input-container.ts +++ b/src/lib/input/input-container.ts @@ -20,7 +20,7 @@ import { MdInputContainerUnsupportedTypeError, MdInputContainerPlaceholderConflictError, MdInputContainerDuplicatedHintError, - MdInputContainerMissingMdInputError + MdInputContainerMissingMdInputError, MdInputContainerFloatingPlaceholderInvalidError } from './input-container-errors'; @@ -38,6 +38,9 @@ const MD_INPUT_INVALID_TYPES = [ 'submit' ]; +/** Valid options for the floatingPlaceholder input binding. */ +export type MD_INPUT_PLACEHOLDER_TYPES = 'always' | 'never' | 'auto'; +const MD_INPUT_PLACEHOLDER_VALUES = ['always', 'never', 'auto']; let nextUniqueId = 0; @@ -249,11 +252,10 @@ export class MdInputContainer implements AfterContentInit { @Input() dividerColor: 'primary' | 'accent' | 'warn' = 'primary'; /** Whether the floating label should always float or not. */ - _shouldAlwaysFloat: boolean = false; + get _shouldAlwaysFloat() { return this._floatingPlaceholder === 'always'; }; /** Whether the placeholder can float or not. */ - _floatingPlaceholder: boolean = true; - + get _canPlaceholderFloat() { return this._floatingPlaceholder !== 'never'; } /** Text for the input hint. */ @Input() @@ -265,15 +267,17 @@ export class MdInputContainer implements AfterContentInit { private _hintLabel = ''; /** - * Whether the placeholder should always float or just show the placeholder when empty. - * If the value is set to null the placeholder will float if text is entered. + * Whether the placeholder should always float, never float or float as the user types. */ @Input() get floatingPlaceholder() { return this._floatingPlaceholder; } - set floatingPlaceholder(value: boolean) { - this._floatingPlaceholder = value == null || coerceBooleanProperty(value); - this._shouldAlwaysFloat = coerceBooleanProperty(value); + set floatingPlaceholder(value: MD_INPUT_PLACEHOLDER_TYPES) { + if (value && MD_INPUT_PLACEHOLDER_VALUES.indexOf(value) === -1) { + throw new MdInputContainerFloatingPlaceholderInvalidError(value); + } + this._floatingPlaceholder = value || 'auto'; } + private _floatingPlaceholder: MD_INPUT_PLACEHOLDER_TYPES = 'auto'; @ContentChild(MdInputDirective) _mdInputChild: MdInputDirective;