Angular 4.x 中有两种表单:
Template-Driven Forms - 模板驱动式表单 (类似于 Angular 1.x 中的表单 )
Reactive Forms - 响应式表单
本文主要介绍 Template-Driven Forms (模板驱动式表单) ,将涉及 ngForm、ngModel、ngModelGroup、表单提交事件、表单验证和异常信息输出等内容。
Contents
ngModule and template-driven forms
Binding ngForm and ngModel
ngModel,[ngModel] and [(ngModel)]
ngModels and ngModelGroup
Template-driven submit
Template-driven error validation
Form base and interface
Form base
<form novalidate> <label> <span>Full name</span> <input type="text" placeholder="Your full name"> </label> <div> <label> <span>Email address</span> <input type="email" placeholder="Your email address"> </label> <label> <span>Confirm address</span> <input type="email" placeholder="Confirm your email address"> </label> </div> <button type="submit">Sign up</button> </form>
接下来我们要实现的功能如下:
绑定 name、email、confirm 输入框的值
为所有输入框添加表单验证功能
显示验证异常信息
表单验证失败时,不允许进行表单提交
表单提交功能
User interface
// signup.interface.ts export interface User { name: string; account: { email: string; confirm: string; } }
ngModule and template-driven forms
在我们继续深入介绍 template-driven 表单前,我们必须在 @NgModule 中导入 @angular/forms 库中的 FormModule:
import { FormsModule } from '@angular/forms'; @NgModule({ imports: [ ..., FormsModule ], declarations: [...], bootstrap: [...] }) export class AppModule {}
友情提示:若使用 template-driven 表单,则导入 FormsModule;若使用 reactive forms,则导入 ReactiveFormsModule。
Template-driven approach
使用模板驱动的表单,我们基本上可以将组件类留空,直到我们需要读取/写入值 (例如提交和设置初始值)。我们将基于上面的定义的基础表单,创建 SignupFormComponent :
signup-form.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'signup-form', template: ` <form novalidate>...</form> ` }) export class SignupFormComponent { constructor() {} }
这是一个很基础的组件,接下来我们导入之前定义的 User 接口,具体如下:
import { User } from './signup.interface'; @Component({...}) export class SignupFormComponent { public user: User = { name: '', account: { email: '', confirm: '' } }; }
初始化 SignupFormComponent 组件类中的用户模型后,我们开始实现第一个功能点:即绑定 name、email、confirm 输入框的值。
Binding ngForm and ngModel
我们从 ngForm 开始,更新后的模板如下:
<form novalidate #f="ngForm"> <label> <span>Full name</span> <input type="text" placeholder="Your full name"> </label> </form>
上面代码中,我们把 ngForm 的值赋值给 #f 变量,通过该变量我们可以方便的获取表单的值。
友情提示: #f 变量的值,是 ngForm 指令的导出对象。
@Directive({ selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,[ngForm]', providers: [formDirectiveProvider], host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'}, outputs: ['ngSubmit'], exportAs: 'ngForm' }) export class NgForm extends ControlContainer implements Form {}
在模板中,我们可以通过以下方式查看表单的值:
{{ f.value | json }} // {}
上面示例 f.value 输出 {},因为此时我们表单中还未绑定任何值。在 Angular 1.x 中我们可以使用 ng-model 指令进行表单数据的双向绑定,接下来我们来看一下 Angular 4.x 中怎么实现数据绑定。
ngModel,[ngModel] and [(ngModel)]
在 Angular 4.x 中 ngModel 有三种不同的语法:
1、ngModel - 直接使用 ngModel 指令,没有使用绑定或关联任何值。
此时,ngModel 将自动关联表单控件的 name 属性,并使用该值作为 ngForm 对象的属性名。
<form novalidate #f="ngForm"> ... <input type="text" placeholder="Your full name" ngModel> ... </form>
友情提示:上面示例中,如果 input 输入框若未设置 name 属性,应用将会抛出异常。ngModel 指令基于输入框的 name 属性,进行绑定。
运行以上代码,f.value 的输入值如下:
{{ f.value | json }} // { name: '' }
非常好,我们已经绑定了 name 输入框的值。但我们应该怎么为输入框设置初始值?
2、[ngModel] = one-way binding syntax (单向绑定语法)
为了设置输入框初始值,我们先要更新一下 SignupFormComponent 组件类的用户模型:
... user: User = { name: 'Semlinker', account: { email: '', confirm: '' } }; ...
更新完用户模型,我们需要同步更新组件模板,具体如下:
<form #f="ngForm"> ... <input type="text" placeholder="Your full name" [ngModel]="user.name"> ... </form>
代码重新运行后,f.value 的输出如下:
{{ f.value | json }} // { name: 'Semlinker' }
从上面示例可以看出,使用 [ngModel] 允许我们通过 this.user.name 设置 name 输入框的初始值,而且该值会自动绑定到 f.value 对象上。
友情提示: [ngModel] 是单向绑定,当表单中 name 输入框的值改变时,不会同步更新 this.user.name
如果想在 name 输入框值变化时,自动同步更新 this.user.name 的值,我们需要使用双向绑定。
3、[(ngModel)] = two-way binding syntax (双向绑定),具体示例如下:
<form #f="ngForm"> ... <input type="text" placeholder="Your full name" [(ngModel)]="user.name"> ... </form>
上面示例成功运行后,我们可以在模板中新增以下代码,然后观察 user 模型的值:
{{ user | json }} // { name: 'Semlinker' }
需要注意的是:以下两种方式是等价的:
<input [(ngModel)]="user.name"> <input [ngModel]="user.name" (ngModelChange)="user.name = $event">
其中 [(ngModel)] 是简写的语法糖。
ngModels and ngModelGroup