diff --git a/src/lib/input/input-container.spec.ts b/src/lib/input/input-container.spec.ts
index 93512f0b857f..0632f4bbce45 100644
--- a/src/lib/input/input-container.spec.ts
+++ b/src/lib/input/input-container.spec.ts
@@ -1,9 +1,9 @@
import {async, TestBed, inject} from '@angular/core/testing';
import {Component} from '@angular/core';
-import {FormsModule, ReactiveFormsModule} from '@angular/forms';
+import {FormsModule, ReactiveFormsModule, FormControl} from '@angular/forms';
import {By} from '@angular/platform-browser';
import {MdInputModule} from './input';
-import {MdInputContainer} from './input-container';
+import {MdInputContainer, MdInputDirective} from './input-container';
import {Platform} from '../core/platform/platform';
import {PlatformModule} from '../core/platform/index';
import {
@@ -43,6 +43,9 @@ describe('MdInputContainer', function () {
MdInputContainerWithDisabled,
MdInputContainerWithRequired,
MdInputContainerWithType,
+ MdInputContainerWithValueBinding,
+ MdInputContainerWithFormControl,
+ MdInputContainerWithStaticPlaceholder,
MdInputContainerMissingMdInputTestController
],
});
@@ -130,6 +133,40 @@ describe('MdInputContainer', function () {
expect(el.classList.contains('md-empty')).toBe(false, 'should not be empty');
}));
+ it('should update the placeholder when input entered', async(() => {
+ let fixture = TestBed.createComponent(MdInputContainerWithStaticPlaceholder);
+ 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');
+ }));
+
+ it('should not be empty when the value set before view init', async(() => {
+ let fixture = TestBed.createComponent(MdInputContainerWithValueBinding);
+ fixture.detectChanges();
+
+ let placeholderEl = fixture.debugElement.query(By.css('.md-input-placeholder')).nativeElement;
+
+ expect(placeholderEl.classList).not.toContain('md-empty');
+
+ fixture.componentInstance.value = '';
+ fixture.detectChanges();
+
+ expect(placeholderEl.classList).toContain('md-empty');
+ }));
+
it('should not treat the number 0 as empty', async(() => {
let fixture = TestBed.createComponent(MdInputContainerZeroTestController);
fixture.detectChanges();
@@ -143,6 +180,20 @@ describe('MdInputContainer', function () {
});
}));
+ it('should update the value when using FormControl.setValue', () => {
+ let fixture = TestBed.createComponent(MdInputContainerWithFormControl);
+ fixture.detectChanges();
+
+ let input = fixture.debugElement.query(By.directive(MdInputDirective))
+ .injector.get(MdInputDirective) as MdInputDirective;
+
+ expect(input.value).toBeFalsy();
+
+ fixture.componentInstance.formControl.setValue('something');
+
+ expect(input.value).toBe('something');
+ });
+
it('should add id', () => {
let fixture = TestBed.createComponent(MdInputContainerTextTestController);
fixture.detectChanges();
@@ -379,6 +430,13 @@ class MdInputContainerPlaceholderElementTestComponent {
placeholder: string = 'Default Placeholder';
}
+@Component({
+ template: ``
+})
+class MdInputContainerWithFormControl {
+ formControl = new FormControl();
+}
+
@Component({
template: ``
})
@@ -482,6 +540,25 @@ class MdInputContainerZeroTestController {
value = 0;
}
+@Component({
+ template: `
+
+
+ `
+})
+class MdInputContainerWithValueBinding {
+ value: string = 'Initial';
+}
+
+@Component({
+ template: `
+
+
+
+ `
+})
+class MdInputContainerWithStaticPlaceholder {}
+
@Component({
template: `
diff --git a/src/lib/input/input-container.ts b/src/lib/input/input-container.ts
index a74a52af9a7d..bb4df7399df3 100644
--- a/src/lib/input/input-container.ts
+++ b/src/lib/input/input-container.ts
@@ -83,10 +83,10 @@ export class MdHint {
'[required]': 'required',
'(blur)': '_onBlur()',
'(focus)': '_onFocus()',
- '(input)': '_onInput()',
+ '(input)': '_onInput()'
}
})
-export class MdInputDirective implements AfterContentInit {
+export class MdInputDirective {
/** Variables used as cache for getters and setters. */
private _type = 'text';
@@ -96,9 +96,6 @@ export class MdInputDirective implements AfterContentInit {
private _id: string;
private _cachedUid: string;
- /** The element's value. */
- value: any;
-
/** Whether the element is focused or not. */
focused = false;
@@ -141,6 +138,10 @@ export class MdInputDirective implements AfterContentInit {
}
}
+ /** The input element's value. */
+ get value() { return this._elementRef.nativeElement.value; }
+ set value(value: string) { this._elementRef.nativeElement.value = value; }
+
/**
* Emits an event when the placeholder changes so that the `md-input-container` can re-validate.
*/
@@ -162,18 +163,9 @@ export class MdInputDirective implements AfterContentInit {
constructor(private _elementRef: ElementRef,
private _renderer: Renderer,
@Optional() public _ngControl: NgControl) {
+
// Force setter to be called in case id was not specified.
this.id = this.id;
-
- if (this._ngControl && this._ngControl.valueChanges) {
- this._ngControl.valueChanges.subscribe((value) => {
- this.value = value;
- });
- }
- }
-
- ngAfterContentInit() {
- this.value = this._elementRef.nativeElement.value;
}
/** Focuses the input element. */
@@ -183,7 +175,15 @@ export class MdInputDirective implements AfterContentInit {
_onBlur() { this.focused = false; }
- _onInput() { this.value = this._elementRef.nativeElement.value; }
+ _onInput() {
+ // This is a noop function and is used to let Angular know whenever the value changes.
+ // Angular will run a new change detection each time the `input` event has been dispatched.
+ // It's necessary that Angular recognizes the value change, because when floatingLabel
+ // is set to false and Angular forms aren't used, the placeholder won't recognize the
+ // value changes and will not disappear.
+ // Listening to the input event wouldn't be necessary when the input is using the
+ // FormsModule or ReactiveFormsModule, because Angular forms also listens to input events.
+ }
/** Make sure the input is a supported type. */
private _validateType() {