fix(forms): set state before emitting a value from ngModelChange (#21514)
Closes #21513. PR Close #21514
This commit is contained in:

committed by
Miško Hevery

parent
0bcfae7cac
commit
9744a1c966
@ -99,9 +99,9 @@ function setUpBlurPipeline(control: FormControl, dir: NgControl): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateControl(control: FormControl, dir: NgControl): void {
|
function updateControl(control: FormControl, dir: NgControl): void {
|
||||||
dir.viewToModelUpdate(control._pendingValue);
|
|
||||||
if (control._pendingDirty) control.markAsDirty();
|
if (control._pendingDirty) control.markAsDirty();
|
||||||
control.setValue(control._pendingValue, {emitModelToViewChange: false});
|
control.setValue(control._pendingValue, {emitModelToViewChange: false});
|
||||||
|
dir.viewToModelUpdate(control._pendingValue);
|
||||||
control._pendingChange = false;
|
control._pendingChange = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1472,6 +1472,36 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat
|
|||||||
expect(required.nativeElement.getAttribute('pattern')).toEqual(null);
|
expect(required.nativeElement.getAttribute('pattern')).toEqual(null);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should update control status', fakeAsync(() => {
|
||||||
|
const fixture = initTest(NgModelChangeState);
|
||||||
|
const inputEl = fixture.debugElement.query(By.css('input'));
|
||||||
|
const inputNativeEl = inputEl.nativeElement;
|
||||||
|
const onNgModelChange = jasmine.createSpy('onNgModelChange');
|
||||||
|
fixture.componentInstance.onNgModelChange = onNgModelChange;
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(onNgModelChange).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
inputNativeEl.value = 'updated';
|
||||||
|
onNgModelChange.and.callFake((ngModel: NgModel) => {
|
||||||
|
expect(ngModel.invalid).toBe(true);
|
||||||
|
expect(ngModel.value).toBe('updated');
|
||||||
|
});
|
||||||
|
dispatchEvent(inputNativeEl, 'input');
|
||||||
|
expect(onNgModelChange).toHaveBeenCalled();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
inputNativeEl.value = '333';
|
||||||
|
onNgModelChange.and.callFake((ngModel: NgModel) => {
|
||||||
|
expect(ngModel.invalid).toBe(false);
|
||||||
|
expect(ngModel.value).toBe('333');
|
||||||
|
});
|
||||||
|
dispatchEvent(inputNativeEl, 'input');
|
||||||
|
expect(onNgModelChange).toHaveBeenCalledTimes(2);
|
||||||
|
tick();
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('IME events', () => {
|
describe('IME events', () => {
|
||||||
@ -1809,6 +1839,17 @@ class NgModelChangesForm {
|
|||||||
log() { this.events.push('fired'); }
|
log() { this.events.push('fired'); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ng-model-change-state',
|
||||||
|
template: `
|
||||||
|
<input #ngModel="ngModel" ngModel [maxlength]="4"
|
||||||
|
(ngModelChange)="onNgModelChange(ngModel)">
|
||||||
|
`
|
||||||
|
})
|
||||||
|
class NgModelChangeState {
|
||||||
|
onNgModelChange = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
function sortedClassList(el: HTMLElement) {
|
function sortedClassList(el: HTMLElement) {
|
||||||
const l = getDOM().classList(el);
|
const l = getDOM().classList(el);
|
||||||
l.sort();
|
l.sort();
|
||||||
|
Reference in New Issue
Block a user