feat(forms): changed forms to capture submit events and fires synthetic ng-submit events

This commit is contained in:
vsavkin 2015-06-05 14:29:50 -07:00
parent 1a4d23742b
commit 5fc23caef7
3 changed files with 77 additions and 11 deletions

View File

@ -1,5 +1,7 @@
import {CONST_EXPR} from 'angular2/src/facade/lang'; import {CONST_EXPR} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
import {Directive, onChange} from 'angular2/angular2'; import {Directive, onChange} from 'angular2/angular2';
import {FORWARD_REF, Binding} from 'angular2/di'; import {FORWARD_REF, Binding} from 'angular2/di';
import {ControlDirective} from './control_directive'; import {ControlDirective} from './control_directive';
@ -57,11 +59,16 @@ const formDirectiveBinding = CONST_EXPR(
selector: '[ng-form-model]', selector: '[ng-form-model]',
hostInjector: [formDirectiveBinding], hostInjector: [formDirectiveBinding],
properties: ['form: ng-form-model'], properties: ['form: ng-form-model'],
lifecycle: [onChange] lifecycle: [onChange],
hostListeners: {
'submit': 'onSubmit()',
},
events: ['ngSubmit']
}) })
export class FormModelDirective extends ControlContainerDirective implements FormDirective { export class FormModelDirective extends ControlContainerDirective implements FormDirective {
form: ControlGroup = null; form: ControlGroup = null;
directives: List<ControlDirective>; directives: List<ControlDirective>;
ngSubmit = new EventEmitter();
constructor() { constructor() {
super(); super();
@ -94,6 +101,11 @@ export class FormModelDirective extends ControlContainerDirective implements For
c.updateValue(value); c.updateValue(value);
} }
onSubmit() {
ObservableWrapper.callNext(this.ngSubmit, null);
return false;
}
_updateDomValue() { _updateDomValue() {
ListWrapper.forEach(this.directives, dir => { ListWrapper.forEach(this.directives, dir => {
var c: any = this.form.find(dir.path); var c: any = this.form.find(dir.path);

View File

@ -1,4 +1,4 @@
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper, ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
import {StringMapWrapper, List, ListWrapper} from 'angular2/src/facade/collection'; import {StringMapWrapper, List, ListWrapper} from 'angular2/src/facade/collection';
import {isPresent, CONST_EXPR} from 'angular2/src/facade/lang'; import {isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
import {Directive} from 'angular2/src/core/annotations/decorators'; import {Directive} from 'angular2/src/core/annotations/decorators';
@ -15,11 +15,16 @@ const formDirectiveBinding = CONST_EXPR(new Binding(
@Directive({ @Directive({
selector: 'form:not([ng-no-form]):not([ng-form-model]),ng-form,[ng-form]', selector: 'form:not([ng-no-form]):not([ng-form-model]),ng-form,[ng-form]',
hostInjector: [formDirectiveBinding] hostInjector: [formDirectiveBinding],
hostListeners: {
'submit': 'onSubmit()',
},
events: ['ngSubmit']
}) })
export class TemplateDrivenFormDirective extends ControlContainerDirective implements export class TemplateDrivenFormDirective extends ControlContainerDirective implements
FormDirective { FormDirective {
form: ControlGroup; form: ControlGroup;
ngSubmit = new EventEmitter();
constructor() { constructor() {
super(); super();
@ -34,12 +39,15 @@ export class TemplateDrivenFormDirective extends ControlContainerDirective imple
get value(): any { return this.form.value; } get value(): any { return this.form.value; }
get errors(): any { return this.form.errors; }
addControl(dir: ControlDirective): void { addControl(dir: ControlDirective): void {
this._later(_ => { this._later(_ => {
var group = this._findContainer(dir.path); var container = this._findContainer(dir.path);
var c = new Control(""); var c = new Control("");
setUpControl(c, dir); setUpControl(c, dir);
group.addControl(dir.name, c); container.addControl(dir.name, c);
c.updateValidity();
}); });
} }
@ -47,23 +55,28 @@ export class TemplateDrivenFormDirective extends ControlContainerDirective imple
removeControl(dir: ControlDirective): void { removeControl(dir: ControlDirective): void {
this._later(_ => { this._later(_ => {
var c = this._findContainer(dir.path); var container = this._findContainer(dir.path);
if (isPresent(c)) c.removeControl(dir.name) if (isPresent(container)) {
container.removeControl(dir.name) container.updateValidity();
}
}); });
} }
addControlGroup(dir: ControlGroupDirective): void { addControlGroup(dir: ControlGroupDirective): void {
this._later(_ => { this._later(_ => {
var group = this._findContainer(dir.path); var container = this._findContainer(dir.path);
var c = new ControlGroup({}); var c = new ControlGroup({});
group.addControl(dir.name, c); container.addControl(dir.name, c);
c.updateValidity();
}); });
} }
removeControlGroup(dir: ControlGroupDirective): void { removeControlGroup(dir: ControlGroupDirective): void {
this._later(_ => { this._later(_ => {
var c = this._findContainer(dir.path); var container = this._findContainer(dir.path);
if (isPresent(c)) c.removeControl(dir.name) if (isPresent(container)) {
container.removeControl(dir.name) container.updateValidity();
}
}); });
} }
@ -74,6 +87,11 @@ export class TemplateDrivenFormDirective extends ControlContainerDirective imple
}); });
} }
onSubmit() {
ObservableWrapper.callNext(this.ngSubmit, null);
return false;
}
_findContainer(path: List<string>): ControlGroup { _findContainer(path: List<string>): ControlGroup {
ListWrapper.removeLast(path); ListWrapper.removeLast(path);
return <ControlGroup>this.form.find(path); return <ControlGroup>this.form.find(path);

View File

@ -74,6 +74,25 @@ export function main() {
}); });
})); }));
it("should emit ng-submit event on submit",
inject([TestBed], fakeAsync(tb => {
var form = new ControlGroup({});
var ctx = MyComp.create({form: form, name: 'old'});
var t =
`<div><form [ng-form-model]="form" (ng-submit)="name='updated'"></form></div>`;
tb.createView(MyComp, {context: ctx, html: t})
.then((view) => {
var form = view.querySelector("form");
dispatchEvent(form, "submit");
tick();
expect(ctx.name).toEqual("updated");
});
})));
it("should work with single controls", inject([TestBed, AsyncTestCompleter], (tb, async) => { it("should work with single controls", inject([TestBed, AsyncTestCompleter], (tb, async) => {
var control = new Control("loginValue"); var control = new Control("loginValue");
var ctx = MyComp.create({form: control}); var ctx = MyComp.create({form: control});
@ -473,6 +492,23 @@ export function main() {
}); });
}))); })));
it("should emit ng-submit event on submit",
inject([TestBed], fakeAsync(tb => {
var ctx = MyComp.create({name: 'old'});
var t = `<div><form (ng-submit)="name='updated'"></form></div>`;
tb.createView(MyComp, {context: ctx, html: t})
.then((view) => {
var form = view.querySelector("form");
dispatchEvent(form, "submit");
tick();
expect(ctx.name).toEqual("updated");
});
})));
it("should not create a template-driven form when ng-no-form is used", it("should not create a template-driven form when ng-no-form is used",
inject([TestBed], fakeAsync(tb => { inject([TestBed], fakeAsync(tb => {
var ctx = MyComp.create({name: null}); var ctx = MyComp.create({name: null});