fix(forms): changes to status not always being emitted to statusChanges observable for async validators. (#42553)
When a FormControl, FormArray, or FormGroup is first constructed, if an async validator is attached, the `statusChanges` observable should receive a message when the validator complete (i.e. pending -> valid/invalid). If the validator was provided as part of the constructor options, it was not fired at construction time, which is fixed in this PR. Fixes #35309. PR Close #42553
This commit is contained in:
parent
56a0582d79
commit
7180ec9e7c
|
@ -1167,7 +1167,7 @@ export class FormControl extends AbstractControl {
|
||||||
// `VALID` or `INVALID`.
|
// `VALID` or `INVALID`.
|
||||||
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
||||||
// to `true` to allow that during the control creation process.
|
// to `true` to allow that during the control creation process.
|
||||||
emitEvent: !!asyncValidator
|
emitEvent: !!this.asyncValidator
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,7 +1433,7 @@ export class FormGroup extends AbstractControl {
|
||||||
// If `asyncValidator` is present, it will trigger control status change from `PENDING` to
|
// If `asyncValidator` is present, it will trigger control status change from `PENDING` to
|
||||||
// `VALID` or `INVALID`. The status should be broadcasted via the `statusChanges` observable,
|
// `VALID` or `INVALID`. The status should be broadcasted via the `statusChanges` observable,
|
||||||
// so we set `emitEvent` to `true` to allow that during the control creation process.
|
// so we set `emitEvent` to `true` to allow that during the control creation process.
|
||||||
emitEvent: !!asyncValidator
|
emitEvent: !!this.asyncValidator
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,7 +1887,7 @@ export class FormArray extends AbstractControl {
|
||||||
// `VALID` or `INVALID`.
|
// `VALID` or `INVALID`.
|
||||||
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
// The status should be broadcasted via the `statusChanges` observable, so we set `emitEvent`
|
||||||
// to `true` to allow that during the control creation process.
|
// to `true` to allow that during the control creation process.
|
||||||
emitEvent: !!asyncValidator
|
emitEvent: !!this.asyncValidator
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1055,6 +1055,23 @@ describe('FormArray', () => {
|
||||||
expect(g.errors).toEqual({'async': true, 'other': true});
|
expect(g.errors).toEqual({'async': true, 'other': true});
|
||||||
expect(g.pending).toEqual(false);
|
expect(g.pending).toEqual(false);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should fire statusChanges events when async validators are added via options object',
|
||||||
|
fakeAsync(() => {
|
||||||
|
// The behavior is tested (in other spec files) for each of the model types (`FormControl`,
|
||||||
|
// `FormGroup` and `FormArray`).
|
||||||
|
let statuses: string[] = [];
|
||||||
|
|
||||||
|
// Create a form control with an async validator added via options object.
|
||||||
|
const asc = new FormArray([], {asyncValidators: [() => Promise.resolve(null)]});
|
||||||
|
|
||||||
|
// Subscribe to status changes.
|
||||||
|
asc.statusChanges.subscribe((status: any) => statuses.push(status));
|
||||||
|
|
||||||
|
// After a tick, the async validator should change status PENDING -> VALID.
|
||||||
|
tick();
|
||||||
|
expect(statuses).toEqual(['VALID']);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('disable() & enable()', () => {
|
describe('disable() & enable()', () => {
|
||||||
|
|
|
@ -879,6 +879,22 @@ describe('FormControl', () => {
|
||||||
tick();
|
tick();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should fire statusChanges events for async validators added via options object',
|
||||||
|
fakeAsync(() => {
|
||||||
|
// The behavior can be tested for each of the model types.
|
||||||
|
let statuses: string[] = [];
|
||||||
|
|
||||||
|
// Create a form control with an async validator added via options object.
|
||||||
|
const asc = new FormControl('', {asyncValidators: [() => Promise.resolve(null)]});
|
||||||
|
|
||||||
|
// Subscribe to status changes.
|
||||||
|
asc.statusChanges.subscribe((status: any) => statuses.push(status));
|
||||||
|
|
||||||
|
// After a tick, the async validator should change status PENDING -> VALID.
|
||||||
|
tick();
|
||||||
|
expect(statuses).toEqual(['VALID']);
|
||||||
|
}));
|
||||||
|
|
||||||
it('should fire an event after the status has been updated to pending', fakeAsync(() => {
|
it('should fire an event after the status has been updated to pending', fakeAsync(() => {
|
||||||
const c = new FormControl('old', Validators.required, asyncValidator('expected'));
|
const c = new FormControl('old', Validators.required, asyncValidator('expected'));
|
||||||
|
|
||||||
|
|
|
@ -819,6 +819,21 @@ describe('FormGroup', () => {
|
||||||
group = new FormGroup({'one': control});
|
group = new FormGroup({'one': control});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should fire statusChanges events for async validators added via options object',
|
||||||
|
fakeAsync(() => {
|
||||||
|
// The behavior can be tested for each of the model types.
|
||||||
|
let statuses: string[] = [];
|
||||||
|
|
||||||
|
// Create a form control with an async validator added via options object.
|
||||||
|
const asc = new FormGroup({}, {asyncValidators: [() => Promise.resolve(null)]});
|
||||||
|
|
||||||
|
// Subscribe to status changes.
|
||||||
|
asc.statusChanges.subscribe((status: any) => statuses.push(status));
|
||||||
|
|
||||||
|
// After a tick, the async validator should change status PENDING -> VALID.
|
||||||
|
tick();
|
||||||
|
expect(statuses).toEqual(['VALID']);
|
||||||
|
}));
|
||||||
|
|
||||||
// TODO(kara): update these tests to use fake Async
|
// TODO(kara): update these tests to use fake Async
|
||||||
it('should fire a statusChange if child has async validation change', done => {
|
it('should fire a statusChange if child has async validation change', done => {
|
||||||
|
|
Loading…
Reference in New Issue