Skip to content

Commit

Permalink
feat(input): option to imperatively float placeholder
Browse files Browse the repository at this point in the history
Refactors the `[floatingPlaceholder]` input to be able to specifiy whether the label should always float or not.

There are three options for the `floatingPlaceholder` input binding now

- If set to `true`, the placeholder will *always* float
- If set to `false`, the placeholder will *never* float
- If set to `null`, the placeholder will float if text is entered.

Closes angular#2466
  • Loading branch information
devversion committed Jan 14, 2017
1 parent 4ab6f30 commit ae3a89a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
3 changes: 2 additions & 1 deletion src/demo-app/input/input-container-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ <h4>Textarea</h4>
</md-input-container>
</p>
<p>
<md-checkbox [(ngModel)]="floatingLabel"> Check to make floating label:</md-checkbox>
<md-checkbox [(ngModel)]="floatingLabel">Toggle Floating Label</md-checkbox>
<button md-button (click)="floatingLabel = null">Reset Floating Label</button>
<md-input-container [floatingPlaceholder]="floatingLabel">
<input mdInput [placeholder]="floatingLabel ? 'Floating label' : 'Not floating label'">
</md-input-container>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/input/input-container.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<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-accent]="dividerColor == 'accent'"
Expand Down
85 changes: 84 additions & 1 deletion src/lib/input/input-container.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ describe('MdInputContainer', function () {
MdInputContainerWithValueBinding,
MdInputContainerWithFormControl,
MdInputContainerWithStaticPlaceholder,
MdInputContainerMissingMdInputTestController
MdInputContainerMissingMdInputTestController,
MdInputContainerWithDynamicPlaceholder
],
});

Expand Down Expand Up @@ -404,6 +405,78 @@ describe('MdInputContainer', function () {
const textarea: HTMLTextAreaElement = fixture.nativeElement.querySelector('textarea');
expect(textarea).not.toBeNull();
});

it('should float when floatingPlaceholder is set to default and text is entered', () => {
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);
fixture.detectChanges();

let inputEl = fixture.debugElement.query(By.css('input'));
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.detectChanges();

expect(labelEl.classList).toContain('md-empty');
expect(labelEl.classList).toContain('md-float');

// Update the value of the input.
inputEl.nativeElement.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 floatingPlaceholder is set to true', () => {
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);
fixture.detectChanges();

let inputEl = fixture.debugElement.query(By.css('input'));
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.nativeElement.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 floatingPlaceholder is set to false', () => {
let fixture = TestBed.createComponent(MdInputContainerWithDynamicPlaceholder);

fixture.componentInstance.shouldFloat = false;
fixture.detectChanges();

let inputEl = fixture.debugElement.query(By.css('input'));
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';

// 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({
Expand Down Expand Up @@ -580,6 +653,16 @@ class MdInputContainerWithValueBinding {
})
class MdInputContainerWithStaticPlaceholder {}

@Component({
template: `
<md-input-container [floatingPlaceholder]="shouldFloat">
<input md-input placeholder="Label">
</md-input-container>`
})
class MdInputContainerWithDynamicPlaceholder {
shouldFloat: boolean = true;
}

@Component({
template: `
<md-input-container>
Expand Down
20 changes: 16 additions & 4 deletions src/lib/input/input-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,13 @@ 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. */
_shouldAlwaysFloat: boolean = false;

/** Whether the placeholder can float or not. */
_floatingPlaceholder: boolean = true;


/** Text for the input hint. */
@Input()
get hintLabel() { return this._hintLabel; }
Expand All @@ -257,11 +264,16 @@ export class MdInputContainer implements AfterContentInit {
}
private _hintLabel = '';

/** Text or the floating placeholder. */
/**
* 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.
*/
@Input()
get floatingPlaceholder(): boolean { return this._floatingPlaceholder; }
set floatingPlaceholder(value) { this._floatingPlaceholder = coerceBooleanProperty(value); }
private _floatingPlaceholder: boolean = true;
get floatingPlaceholder() { return this._floatingPlaceholder; }
set floatingPlaceholder(value: boolean) {
this._floatingPlaceholder = value == null || coerceBooleanProperty(value);
this._shouldAlwaysFloat = coerceBooleanProperty(value);
}

@ContentChild(MdInputDirective) _mdInputChild: MdInputDirective;

Expand Down

0 comments on commit ae3a89a

Please sign in to comment.