mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(input): properly determine input value (#2455)
Fixes #2441. Fixes #2363
This commit is contained in:
@@ -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: `<md-input-container><input md-input [formControl]="formControl"></md-input-container>`
|
||||
})
|
||||
class MdInputContainerWithFormControl {
|
||||
formControl = new FormControl();
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `<md-input-container><input mdInput [placeholder]="placeholder"></md-input-container>`
|
||||
})
|
||||
@@ -482,6 +540,25 @@ class MdInputContainerZeroTestController {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container>
|
||||
<input mdInput placeholder="Label" [value]="value">
|
||||
</md-input-container>`
|
||||
})
|
||||
class MdInputContainerWithValueBinding {
|
||||
value: string = 'Initial';
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container [floatingPlaceholder]="false">
|
||||
<input md-input placeholder="Label">
|
||||
</md-input-container>
|
||||
`
|
||||
})
|
||||
class MdInputContainerWithStaticPlaceholder {}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<md-input-container>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user