Form submit event (#11989)

* feat(forms): ngSubmit event exposes $event from original submit event as local variable

Modify NgForm directive and FormGroup directive to expose the original submit event as $event in the ngSubmit event. Modify docs to reflect changes.

This resolves #10920.

* refactor: code cleanup
This commit is contained in:
Connor Wyatt 2016-10-11 23:49:36 +01:00 committed by Tobias Bosch
parent 5effc330ed
commit 17e3410d98
5 changed files with 32 additions and 26 deletions

View File

@ -48,7 +48,8 @@ const resolvedPromise = Promise.resolve(null);
* sub-groups within the form. * sub-groups within the form.
* *
* You can listen to the directive's `ngSubmit` event to be notified when the user has * You can listen to the directive's `ngSubmit` event to be notified when the user has
* triggered a form submission. * triggered a form submission. The `ngSubmit` event will be emitted with the original form
* submission event.
* *
* {@example forms/ts/simpleForm/simple_form_example.ts region='Component'} * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
* *
@ -61,7 +62,7 @@ const resolvedPromise = Promise.resolve(null);
@Directive({ @Directive({
selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,[ngForm]', selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,[ngForm]',
providers: [formDirectiveProvider], providers: [formDirectiveProvider],
host: {'(submit)': 'onSubmit()', '(reset)': 'onReset()'}, host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
outputs: ['ngSubmit'], outputs: ['ngSubmit'],
exportAs: 'ngForm' exportAs: 'ngForm'
}) })
@ -102,7 +103,7 @@ export class NgForm extends ControlContainer implements Form {
removeControl(dir: NgModel): void { removeControl(dir: NgModel): void {
resolvedPromise.then(() => { resolvedPromise.then(() => {
var container = this._findContainer(dir.path); const container = this._findContainer(dir.path);
if (isPresent(container)) { if (isPresent(container)) {
container.removeControl(dir.name); container.removeControl(dir.name);
} }
@ -111,8 +112,8 @@ export class NgForm extends ControlContainer implements Form {
addFormGroup(dir: NgModelGroup): void { addFormGroup(dir: NgModelGroup): void {
resolvedPromise.then(() => { resolvedPromise.then(() => {
var container = this._findContainer(dir.path); const container = this._findContainer(dir.path);
var group = new FormGroup({}); const group = new FormGroup({});
setUpFormContainer(group, dir); setUpFormContainer(group, dir);
container.registerControl(dir.name, group); container.registerControl(dir.name, group);
group.updateValueAndValidity({emitEvent: false}); group.updateValueAndValidity({emitEvent: false});
@ -121,7 +122,7 @@ export class NgForm extends ControlContainer implements Form {
removeFormGroup(dir: NgModelGroup): void { removeFormGroup(dir: NgModelGroup): void {
resolvedPromise.then(() => { resolvedPromise.then(() => {
var container = this._findContainer(dir.path); const container = this._findContainer(dir.path);
if (isPresent(container)) { if (isPresent(container)) {
container.removeControl(dir.name); container.removeControl(dir.name);
} }
@ -132,16 +133,16 @@ export class NgForm extends ControlContainer implements Form {
updateModel(dir: NgControl, value: any): void { updateModel(dir: NgControl, value: any): void {
resolvedPromise.then(() => { resolvedPromise.then(() => {
var ctrl = <FormControl>this.form.get(dir.path); const ctrl = <FormControl>this.form.get(dir.path);
ctrl.setValue(value); ctrl.setValue(value);
}); });
} }
setValue(value: {[key: string]: any}): void { this.control.setValue(value); } setValue(value: {[key: string]: any}): void { this.control.setValue(value); }
onSubmit(): boolean { onSubmit($event: Event): boolean {
this._submitted = true; this._submitted = true;
this.ngSubmit.emit(null); this.ngSubmit.emit($event);
return false; return false;
} }

View File

@ -44,6 +44,10 @@ export const formDirectiveProvider: any = {
* its {@link AbstractControl.statusChanges} event to be notified when the validation status is * its {@link AbstractControl.statusChanges} event to be notified when the validation status is
* re-calculated. * re-calculated.
* *
* Furthermore, you can listen to the directive's `ngSubmit` event to be notified when the user has
* triggered a form submission. The `ngSubmit` event will be emitted with the original form
* submission event.
*
* ### Example * ### Example
* *
* In this example, we create form controls for first name and last name. * In this example, we create form controls for first name and last name.
@ -59,7 +63,7 @@ export const formDirectiveProvider: any = {
@Directive({ @Directive({
selector: '[formGroup]', selector: '[formGroup]',
providers: [formDirectiveProvider], providers: [formDirectiveProvider],
host: {'(submit)': 'onSubmit()', '(reset)': 'onReset()'}, host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
exportAs: 'ngForm' exportAs: 'ngForm'
}) })
export class FormGroupDirective extends ControlContainer implements Form, export class FormGroupDirective extends ControlContainer implements Form,
@ -107,7 +111,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
removeControl(dir: FormControlName): void { ListWrapper.remove(this.directives, dir); } removeControl(dir: FormControlName): void { ListWrapper.remove(this.directives, dir); }
addFormGroup(dir: FormGroupName): void { addFormGroup(dir: FormGroupName): void {
var ctrl: any = this.form.get(dir.path); const ctrl: any = this.form.get(dir.path);
setUpFormContainer(ctrl, dir); setUpFormContainer(ctrl, dir);
ctrl.updateValueAndValidity({emitEvent: false}); ctrl.updateValueAndValidity({emitEvent: false});
} }
@ -117,7 +121,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
getFormGroup(dir: FormGroupName): FormGroup { return <FormGroup>this.form.get(dir.path); } getFormGroup(dir: FormGroupName): FormGroup { return <FormGroup>this.form.get(dir.path); }
addFormArray(dir: FormArrayName): void { addFormArray(dir: FormArrayName): void {
var ctrl: any = this.form.get(dir.path); const ctrl: any = this.form.get(dir.path);
setUpFormContainer(ctrl, dir); setUpFormContainer(ctrl, dir);
ctrl.updateValueAndValidity({emitEvent: false}); ctrl.updateValueAndValidity({emitEvent: false});
} }
@ -127,13 +131,13 @@ export class FormGroupDirective extends ControlContainer implements Form,
getFormArray(dir: FormArrayName): FormArray { return <FormArray>this.form.get(dir.path); } getFormArray(dir: FormArrayName): FormArray { return <FormArray>this.form.get(dir.path); }
updateModel(dir: FormControlName, value: any): void { updateModel(dir: FormControlName, value: any): void {
var ctrl  = <FormControl>this.form.get(dir.path); const ctrl  = <FormControl>this.form.get(dir.path);
ctrl.setValue(value); ctrl.setValue(value);
} }
onSubmit(): boolean { onSubmit($event: Event): boolean {
this._submitted = true; this._submitted = true;
this.ngSubmit.emit(null); this.ngSubmit.emit($event);
return false; return false;
} }

View File

@ -529,17 +529,17 @@ export function main() {
}); });
describe('submit and reset events', () => { describe('submit and reset events', () => {
it('should emit ngSubmit event on submit', () => { it('should emit ngSubmit event with the original submit event on submit', () => {
const fixture = TestBed.createComponent(FormGroupComp); const fixture = TestBed.createComponent(FormGroupComp);
fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')}); fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')});
fixture.componentInstance.data = 'should be changed'; fixture.componentInstance.event = null;
fixture.detectChanges(); fixture.detectChanges();
const formEl = fixture.debugElement.query(By.css('form')).nativeElement; const formEl = fixture.debugElement.query(By.css('form')).nativeElement;
dispatchEvent(formEl, 'submit'); dispatchEvent(formEl, 'submit');
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.componentInstance.data).toEqual('submitted'); expect(fixture.componentInstance.event.type).toEqual('submit');
}); });
it('should mark formGroup as submitted on submit event', () => { it('should mark formGroup as submitted on submit event', () => {
@ -1760,7 +1760,7 @@ class FormControlComp {
@Component({ @Component({
selector: 'form-group-comp', selector: 'form-group-comp',
template: ` template: `
<form [formGroup]="form" (ngSubmit)="data='submitted'"> <form [formGroup]="form" (ngSubmit)="event=$event">
<input type="text" formControlName="login"> <input type="text" formControlName="login">
</form> </form>
` `
@ -1769,7 +1769,7 @@ class FormGroupComp {
control: FormControl; control: FormControl;
form: FormGroup; form: FormGroup;
myGroup: FormGroup; myGroup: FormGroup;
data: string; event: Event;
} }
@Component({ @Component({

View File

@ -237,15 +237,15 @@ export function main() {
}); });
describe('submit and reset events', () => { describe('submit and reset events', () => {
it('should emit ngSubmit event on submit', fakeAsync(() => { it('should emit ngSubmit event with the original submit event on submit', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelForm); const fixture = TestBed.createComponent(NgModelForm);
fixture.componentInstance.name = 'old'; fixture.componentInstance.event = null;
const form = fixture.debugElement.query(By.css('form')); const form = fixture.debugElement.query(By.css('form'));
dispatchEvent(form.nativeElement, 'submit'); dispatchEvent(form.nativeElement, 'submit');
tick(); tick();
expect(fixture.componentInstance.name).toEqual('submitted'); expect(fixture.componentInstance.event.type).toEqual('submit');
})); }));
it('should mark NgForm as submitted on submit event', fakeAsync(() => { it('should mark NgForm as submitted on submit event', fakeAsync(() => {
@ -898,13 +898,14 @@ class StandaloneNgModel {
@Component({ @Component({
selector: 'ng-model-form', selector: 'ng-model-form',
template: ` template: `
<form (ngSubmit)="name='submitted'" (reset)="onReset()"> <form (ngSubmit)="event=$event" (reset)="onReset()">
<input name="name" [(ngModel)]="name" minlength="10" [ngModelOptions]="options"> <input name="name" [(ngModel)]="name" minlength="10" [ngModelOptions]="options">
</form> </form>
` `
}) })
class NgModelForm { class NgModelForm {
name: string; name: string;
event: Event;
options = {}; options = {};
onReset() {} onReset() {}

View File

@ -299,7 +299,7 @@ export declare class FormGroupDirective extends ControlContainer implements Form
getFormGroup(dir: FormGroupName): FormGroup; getFormGroup(dir: FormGroupName): FormGroup;
ngOnChanges(changes: SimpleChanges): void; ngOnChanges(changes: SimpleChanges): void;
onReset(): void; onReset(): void;
onSubmit(): boolean; onSubmit($event: Event): boolean;
removeControl(dir: FormControlName): void; removeControl(dir: FormControlName): void;
removeFormArray(dir: FormArrayName): void; removeFormArray(dir: FormArrayName): void;
removeFormGroup(dir: FormGroupName): void; removeFormGroup(dir: FormGroupName): void;
@ -382,7 +382,7 @@ export declare class NgForm extends ControlContainer implements Form {
getControl(dir: NgModel): FormControl; getControl(dir: NgModel): FormControl;
getFormGroup(dir: NgModelGroup): FormGroup; getFormGroup(dir: NgModelGroup): FormGroup;
onReset(): void; onReset(): void;
onSubmit(): boolean; onSubmit($event: Event): boolean;
removeControl(dir: NgModel): void; removeControl(dir: NgModel): void;
removeFormGroup(dir: NgModelGroup): void; removeFormGroup(dir: NgModelGroup): void;
resetForm(value?: any): void; resetForm(value?: any): void;