feat(ngModel):handle ime events (#13891)

PR Close: #13891
This commit is contained in:
执衡 2017-01-12 20:02:45 +08:00 committed by Miško Hevery
parent c7245189e2
commit c5ea03a023
3 changed files with 47 additions and 2 deletions

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
import {Directive, Host, HostListener, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
import {EventEmitter} from '../facade/async';
import {FormControl} from '../model';
@ -115,6 +115,7 @@ export class NgModel extends NgControl implements OnChanges,
_control = new FormControl();
/** @internal */
_registered = false;
private _composing = false;
viewModel: any;
@Input() name: string;
@ -124,6 +125,15 @@ export class NgModel extends NgControl implements OnChanges,
@Output('ngModelChange') update = new EventEmitter();
@HostListener('compositionstart')
compositionStart(): void { this._composing = true; }
@HostListener('compositionend')
compositionEnd(): void {
this._composing = false;
this.update.emit(this.viewModel);
}
constructor(@Optional() @Host() parent: ControlContainer,
@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>,
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<Validator|AsyncValidatorFn>,
@ -167,7 +177,7 @@ export class NgModel extends NgControl implements OnChanges,
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;
this.update.emit(newValue);
!this._composing && this.update.emit(newValue);
}
private _setUpControl(): void {

View File

@ -42,6 +42,39 @@ export function main() {
expect(fixture.componentInstance.name).toEqual('updatedValue');
}));
it('should ngModel hold ime events until compositionend', fakeAsync(() => {
const fixture = TestBed.createComponent(StandaloneNgModel);
// model -> view
const inputEl = fixture.debugElement.query(By.css('input'));
const inputNativeEl = inputEl.nativeElement;
fixture.componentInstance.name = 'oldValue';
fixture.detectChanges();
tick();
expect(inputNativeEl.value).toEqual('oldValue');
// view -> model
inputEl.triggerEventHandler('compositionstart', null);
inputNativeEl.value = 'updatedValue';
dispatchEvent(inputNativeEl, 'input');
tick();
// should ngModel not update when compositionstart
expect(fixture.componentInstance.name).toEqual('oldValue');
inputEl.triggerEventHandler('compositionend', null);
fixture.detectChanges();
tick();
// should ngModel update when compositionend
expect(fixture.componentInstance.name).toEqual('updatedValue');
}));
it('should support ngModel registration with a parent form', fakeAsync(() => {
const fixture = initTest(NgModelForm);
fixture.componentInstance.name = 'Nancy';

View File

@ -435,6 +435,8 @@ export declare class NgModel extends NgControl implements OnChanges, OnDestroy {
validator: ValidatorFn;
viewModel: any;
constructor(parent: ControlContainer, validators: Array<Validator | ValidatorFn>, asyncValidators: Array<Validator | AsyncValidatorFn>, valueAccessors: ControlValueAccessor[]);
compositionEnd(): void;
compositionStart(): void;
ngOnChanges(changes: SimpleChanges): void;
ngOnDestroy(): void;
viewToModelUpdate(newValue: any): void;