mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(forms): Add event for forms submitted & reset (#55667)
This commit adds 2 new events to the unified control event observable. PR Close #55667
This commit is contained in:
parent
c1915f19c6
commit
fedeaac8ba
6 changed files with 89 additions and 2 deletions
|
|
@ -565,6 +565,13 @@ export interface FormRecord<TControl> {
|
|||
}): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class FormResetEvent extends ControlEvent {
|
||||
constructor(source: AbstractControl);
|
||||
// (undocumented)
|
||||
readonly source: AbstractControl;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class FormsModule {
|
||||
static withConfig(opts: {
|
||||
|
|
@ -578,6 +585,13 @@ export class FormsModule {
|
|||
static ɵmod: i0.ɵɵNgModuleDeclaration<FormsModule, [typeof i1_2.NgModel, typeof i2_2.NgModelGroup, typeof i3_2.NgForm], never, [typeof i4_2.ɵInternalFormsSharedModule, typeof i1_2.NgModel, typeof i2_2.NgModelGroup, typeof i3_2.NgForm]>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class FormSubmittedEvent extends ControlEvent {
|
||||
constructor(source: AbstractControl);
|
||||
// (undocumented)
|
||||
readonly source: AbstractControl;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const isFormArray: (control: unknown) => control is FormArray<any>;
|
||||
|
||||
|
|
|
|||
|
|
@ -248,6 +248,12 @@
|
|||
{
|
||||
"name": "FormRecord"
|
||||
},
|
||||
{
|
||||
"name": "FormResetEvent"
|
||||
},
|
||||
{
|
||||
"name": "FormSubmittedEvent"
|
||||
},
|
||||
{
|
||||
"name": "FormsExampleModule"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from '../valid
|
|||
|
||||
import {FormControlName} from './form_control_name';
|
||||
import {FormArrayName, FormGroupName} from './form_group_name';
|
||||
import {FormResetEvent, FormSubmittedEvent} from '../../model/abstract_model';
|
||||
|
||||
const formDirectiveProvider: Provider = {
|
||||
provide: ControlContainer,
|
||||
|
|
@ -302,6 +303,8 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan
|
|||
(this as Writable<this>).submitted = true;
|
||||
syncPendingControls(this.form, this.directives);
|
||||
this.ngSubmit.emit($event);
|
||||
this.form._events.next(new FormSubmittedEvent(this.control));
|
||||
|
||||
// Forms with `method="dialog"` have some special behavior that won't reload the page and that
|
||||
// shouldn't be prevented. Note that we need to null check the `event` and the `target`, because
|
||||
// some internal apps call this method directly with the wrong arguments.
|
||||
|
|
@ -325,6 +328,7 @@ export class FormGroupDirective extends ControlContainer implements Form, OnChan
|
|||
resetForm(value: any = undefined): void {
|
||||
this.form.reset(value);
|
||||
(this as Writable<this>).submitted = false;
|
||||
this.form._events.next(new FormResetEvent(this.form));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ export {
|
|||
AbstractControlOptions,
|
||||
ControlEvent,
|
||||
FormControlStatus,
|
||||
FormResetEvent,
|
||||
FormSubmittedEvent,
|
||||
PristineChangeEvent as PristineEvent,
|
||||
StatusChangeEvent as StatusEvent,
|
||||
TouchedChangeEvent as TouchedEvent,
|
||||
|
|
|
|||
|
|
@ -144,6 +144,27 @@ export class StatusChangeEvent extends ControlEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event fired when a form is submitted
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export class FormSubmittedEvent extends ControlEvent {
|
||||
constructor(public readonly source: AbstractControl) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Event fired when a form is reset.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export class FormResetEvent extends ControlEvent {
|
||||
constructor(public readonly source: AbstractControl) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets validators from either an options object or given validators.
|
||||
*/
|
||||
|
|
@ -683,7 +704,7 @@ export abstract class AbstractControl<TValue = any, TRawValue extends TValue = T
|
|||
*
|
||||
* @internal
|
||||
*/
|
||||
private readonly _events = new Subject<ControlEvent<TValue>>();
|
||||
readonly _events = new Subject<ControlEvent<TValue>>();
|
||||
|
||||
/**
|
||||
* A multicasting observable that emits an event every time the state of the control changes.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import {
|
|||
FormControl,
|
||||
FormControlDirective,
|
||||
FormControlName,
|
||||
FormControlState,
|
||||
FormGroup,
|
||||
FormGroupDirective,
|
||||
FormsModule,
|
||||
|
|
@ -51,6 +50,8 @@ import {map, tap} from 'rxjs/operators';
|
|||
import {
|
||||
ControlEvent,
|
||||
FormControlStatus,
|
||||
FormResetEvent,
|
||||
FormSubmittedEvent,
|
||||
PristineChangeEvent,
|
||||
StatusChangeEvent,
|
||||
TouchedChangeEvent,
|
||||
|
|
@ -1391,6 +1392,45 @@ describe('reactive forms integration tests', () => {
|
|||
fc.markAsDirty({emitEvent: false});
|
||||
expect(fcEvents.length).toBe(0);
|
||||
});
|
||||
|
||||
it('formControl should emit an event when resetting a form', () => {
|
||||
const fixture = initTest(FormGroupComp);
|
||||
const form = new FormGroup({'login': new FormControl('', Validators.required)});
|
||||
fixture.componentInstance.form = form;
|
||||
fixture.detectChanges();
|
||||
|
||||
const formGroupDir = fixture.debugElement.children[0].injector.get(FormGroupDirective);
|
||||
|
||||
const events: ControlEvent[] = [];
|
||||
fixture.componentInstance.form.events.subscribe((event) => events.push(event));
|
||||
formGroupDir.resetForm();
|
||||
|
||||
expect(events.length).toBe(4);
|
||||
expect(events[0]).toBeInstanceOf(TouchedChangeEvent);
|
||||
expect(events[1]).toBeInstanceOf(ValueChangeEvent);
|
||||
expect(events[2]).toBeInstanceOf(StatusChangeEvent);
|
||||
|
||||
// The event that matters
|
||||
expect(events[3]).toBeInstanceOf(FormResetEvent);
|
||||
expect(events[3].source).toBe(form);
|
||||
});
|
||||
|
||||
it('formControl should emit an event when submitting a form', () => {
|
||||
const fixture = initTest(FormGroupComp);
|
||||
const form = new FormGroup({'login': new FormControl('', Validators.required)});
|
||||
fixture.componentInstance.form = form;
|
||||
fixture.detectChanges();
|
||||
|
||||
const formGroupDir = fixture.debugElement.children[0].injector.get(FormGroupDirective);
|
||||
|
||||
const events: ControlEvent[] = [];
|
||||
fixture.componentInstance.form.events.subscribe((event) => events.push(event));
|
||||
formGroupDir.onSubmit({} as any);
|
||||
|
||||
expect(events.length).toBe(1);
|
||||
expect(events[0]).toBeInstanceOf(FormSubmittedEvent);
|
||||
expect(events[0].source).toBe(form);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setting status classes', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue