fix(forms): update dirty before emitting value change (#10362)
Closes #5328
This commit is contained in:
parent
a32c4ad2f0
commit
7c76a75452
|
@ -45,8 +45,8 @@ export function setUpControl(control: FormControl, dir: NgControl): void {
|
|||
// view -> model
|
||||
dir.valueAccessor.registerOnChange((newValue: any) => {
|
||||
dir.viewToModelUpdate(newValue);
|
||||
control.updateValue(newValue, {emitModelToViewChange: false});
|
||||
control.markAsDirty();
|
||||
control.updateValue(newValue, {emitModelToViewChange: false});
|
||||
});
|
||||
|
||||
control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
|
||||
|
|
|
@ -409,9 +409,9 @@ export class FormControl extends AbstractControl {
|
|||
}
|
||||
|
||||
reset(value: any = null, {onlySelf}: {onlySelf?: boolean} = {}): void {
|
||||
this.updateValue(value, {onlySelf: onlySelf});
|
||||
this.markAsPristine({onlySelf: onlySelf});
|
||||
this.markAsUntouched({onlySelf: onlySelf});
|
||||
this.updateValue(value, {onlySelf: onlySelf});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -236,6 +236,33 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should mark controls as dirty before emitting a value change event',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
const login = new FormControl('oldValue');
|
||||
const form = new FormGroup({'login': login});
|
||||
|
||||
const t = `<div [formGroup]="form">
|
||||
<input type="text" formControlName="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => {
|
||||
fixture.debugElement.componentInstance.form = form;
|
||||
fixture.detectChanges();
|
||||
|
||||
login.valueChanges.subscribe(() => {
|
||||
expect(login.dirty).toBe(true);
|
||||
async.done();
|
||||
});
|
||||
|
||||
const loginEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
loginEl.value = 'newValue';
|
||||
|
||||
dispatchEvent(loginEl, 'input');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should clear value in UI when form resets programmatically',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
|
@ -289,6 +316,37 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should mark control as pristine before emitting a value change event when resetting ',
|
||||
inject(
|
||||
[TestComponentBuilder, AsyncTestCompleter],
|
||||
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
|
||||
const login = new FormControl('oldValue');
|
||||
const form = new FormGroup({'login': login});
|
||||
|
||||
const t = `<div [formGroup]="form">
|
||||
<input type="text" formControlName="login">
|
||||
</div>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => {
|
||||
fixture.debugElement.componentInstance.form = form;
|
||||
fixture.detectChanges();
|
||||
|
||||
const loginEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
loginEl.value = 'newValue';
|
||||
|
||||
dispatchEvent(loginEl, 'input');
|
||||
|
||||
expect(login.pristine).toBe(false);
|
||||
|
||||
login.valueChanges.subscribe(() => {
|
||||
expect(login.pristine).toBe(true);
|
||||
async.done();
|
||||
});
|
||||
|
||||
form.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support form arrays',
|
||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
const cityArray = new FormArray([new FormControl('SF'), new FormControl('NY')]);
|
||||
|
|
|
@ -369,6 +369,58 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should mark controls as dirty before emitting a value change event',
|
||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
|
||||
const t = `<form>
|
||||
<input type="text" name="login" ngModel>
|
||||
</form>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const form = fixture.debugElement.children[0].injector.get(NgForm).form;
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
form.find('login').valueChanges.subscribe(
|
||||
() => { expect(form.find('login').dirty).toBe(true); });
|
||||
|
||||
const loginEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
loginEl.value = 'newValue';
|
||||
|
||||
dispatchEvent(loginEl, 'input');
|
||||
});
|
||||
})));
|
||||
|
||||
it('should mark control as pristine before emitting a value change event when resetting ',
|
||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
|
||||
const t = `<form>
|
||||
<input type="text" name="login" ngModel>
|
||||
</form>`;
|
||||
|
||||
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => {
|
||||
fixture.detectChanges();
|
||||
|
||||
const form = fixture.debugElement.children[0].injector.get(NgForm).form;
|
||||
const formEl = fixture.debugElement.query(By.css('form')).nativeElement;
|
||||
const loginEl = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
loginEl.value = 'newValue';
|
||||
dispatchEvent(loginEl, 'input');
|
||||
|
||||
expect(form.find('login').pristine).toBe(false);
|
||||
|
||||
form.find('login').valueChanges.subscribe(
|
||||
() => { expect(form.find('login').pristine).toBe(true); });
|
||||
|
||||
dispatchEvent(formEl, 'reset');
|
||||
});
|
||||
})));
|
||||
|
||||
describe('radio value accessor', () => {
|
||||
it('should support <type=radio>',
|
||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
|
|
Loading…
Reference in New Issue