Angular.js 4.x中表单Template-Driven Forms详解
Angular4.x中有两种表单:
- Template-DrivenForms-模板驱动式表单(类似于Angular1.x中的表单)
- ReactiveForms-响应式表单
本文主要介绍Template-DrivenForms(模板驱动式表单),将涉及ngForm、ngModel、ngModelGroup、表单提交事件、表单验证和异常信息输出等内容。
Contents
- ngModuleandtemplate-drivenforms
- BindingngFormandngModel
- ngModel,[ngModel]and[(ngModel)]
- ngModelsandngModelGroup
- Template-drivensubmit
- Template-drivenerrorvalidation
Formbaseandinterface
Formbase
Signup
接下来我们要实现的功能如下:
- 绑定name、email、confirm输入框的值
- 为所有输入框添加表单验证功能
- 显示验证异常信息
- 表单验证失败时,不允许进行表单提交
- 表单提交功能
Userinterface
//signup.interface.ts exportinterfaceUser{ name:string; account:{ email:string; confirm:string; } }
ngModuleandtemplate-drivenforms
在我们继续深入介绍template-driven表单前,我们必须在@NgModule中导入@angular/forms库中的FormModule:
import{FormsModule}from'@angular/forms'; @NgModule({ imports:[ ..., FormsModule ], declarations:[...], bootstrap:[...] }) exportclassAppModule{}
友情提示:若使用template-driven表单,则导入FormsModule;若使用reactiveforms,则导入ReactiveFormsModule。
Template-drivenapproach
使用模板驱动的表单,我们基本上可以将组件类留空,直到我们需要读取/写入值(例如提交和设置初始值)。我们将基于上面的定义的基础表单,创建SignupFormComponent:
signup-form.component.ts
import{Component}from'@angular/core'; @Component({ selector:'signup-form', template:`... ` }) exportclassSignupFormComponent{ constructor(){} }
这是一个很基础的组件,接下来我们导入之前定义的User接口,具体如下:
import{User}from'./signup.interface'; @Component({...}) exportclassSignupFormComponent{ publicuser:User={ name:'', account:{ email:'', confirm:'' } }; }
初始化SignupFormComponent组件类中的用户模型后,我们开始实现第一个功能点:即绑定name、email、confirm输入框的值。
BindingngFormandngModel
我们从ngForm开始,更新后的模板如下:
上面代码中,我们把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' }) exportclassNgFormextendsControlContainerimplementsForm{}
在模板中,我们可以通过以下方式查看表单的值:
{{f.value|json}}//{}
上面示例f.value输出{},因为此时我们表单中还未绑定任何值。在Angular1.x中我们可以使用ng-model指令进行表单数据的双向绑定,接下来我们来看一下Angular4.x中怎么实现数据绑定。
ngModel,[ngModel]and[(ngModel)]
在Angular4.x中ngModel有三种不同的语法:
1、ngModel-直接使用ngModel指令,没有使用绑定或关联任何值。
此时,ngModel将自动关联表单控件的name属性,并使用该值作为ngForm对象的属性名。
... ...
友情提示:上面示例中,如果input输入框若未设置name属性,应用将会抛出异常。ngModel指令基于输入框的name属性,进行绑定。
运行以上代码,f.value的输入值如下:
{{f.value|json}}//{name:''}
非常好,我们已经绑定了name输入框的值。但我们应该怎么为输入框设置初始值?
2、[ngModel]=one-waybindingsyntax(单向绑定语法)
为了设置输入框初始值,我们先要更新一下SignupFormComponent组件类的用户模型:
... user:User={ name:'Semlinker', account:{ email:'', confirm:'' } }; ...
更新完用户模型,我们需要同步更新组件模板,具体如下:
代码重新运行后,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-waybindingsyntax(双向绑定),具体示例如下:
上面示例成功运行后,我们可以在模板中新增以下代码,然后观察user模型的值:
{{user|json}}//{name:'Semlinker'}
需要注意的是:以下两种方式是等价的:
其中[(ngModel)]是简写的语法糖。
ngModelsandngModelGroup
我们已经介绍了ngForm和ngModel的基础用法,现在我们来完善剩下的内容。SignupFormComponent组件类的用户模型中,包含了一个嵌套属性account,account对象中包含email和confirm属性,分为表示邮件地址和重复确认的邮件地址。针对这种场景,Angular4.x为我们提供了ngModelGroup指令,具体示例如下:
使用ngModelGroup指令后,我们的DOM结构将更加合理:
ngForm->'#f' ngModel->'name' ngModelGroup->'account' ->ngModel->'email' ->ngModel->'confirm'
以上代码成功运行后,浏览器中页面显示的结果:
//{name:'Semlinker',account:{email:'',confirm:''}} {{f.value|json}}
此时我们已经完成了表单数据绑定,接下来我们来为表单增加提交逻辑。
Template-drivensubmit
Angular表单中提供了ngSubmit输出属性,用于监听表单的提交事件:
...
当用户提交表单时,我们将会把f作为参数,调用ngSubmit关联的onSubmit()方法。onSubmit()方法的具体实现如下:
exportclassSignupFormComponent{ user:User={...}; onSubmit({value,valid}:{value:User,valid:boolean}){ console.log(value,valid); } }
上面代码中,我们使用Objectdestructuring(对象解构)的方式,从#f引用对象中获取value和valid属性的值。其中value的值,就是f.value的值。表单的数据绑定方式和提交逻辑已经介绍完了,是该介绍表单实际应用中,一个重要的环节—表单验证。
Template-drivenerrorvalidation
在为表单项添加验证规则前,我们先来更新一下SignupFormComponent组件中的Signup按钮,确保在表单验证不通过时,不允许用户执行表单提交操作。
更新后的代码如下:
... Signup
以上代码我们通过f.invalid获取表单当前的验证状态(验证不通过时该值为true),来控制按钮的disabled属性。
接下来开始进入正题,为表单添加验证规则:
上面代码中,我们为每个input表单控件,添加了required(必填项)的验证规则。一切都那么简单,剩下的问题就是如何获取验证失败的异常消息。
皇上,您还记得当年大明湖畔的夏雨荷吗?—No,No,No!我只记得安谷拉(angular)湖畔的美女(f)。
#f引用对象中有一个controls属性,通过该属性,我们就可以获取表单控件的验证信息,下面示例演示了如何获取name表单控件验证的异常信息:
{{f.controls.name?.errors|json}}
f.controls.name?.errors的值是null或undefined时,表示验证成功。
友情提示:?.prop称为安全导航操作符,用于告诉Angularprop的值可能不存在。
接下来为我们的name表单控件,添加显示异常信息的代码:
Nameisrequired
虽然我们已经可以获取某个表单项的验证信息,但有没有觉得使用f.controls.name?.errors这种方式,太麻烦了。那么有没有更简单的方式呢?我的答案是-Yes!废话不多说,马上看示例:
Nameisrequired
(备注:此处一定要使用#userName="ngModel")
以上代码成功运行后,我们在浏览器中看到了异常信息,为了避免一开始就显示异常信息,我们可以更新一下*ngIf表达式的验证逻辑:
Nameisrequired
除了使用required验证规则之外,我们还可以使用minlength(最小长度)、maxlength(最大长度)等验证规则,下面我们继续来完善SignupFormComponent组件的功能,即为其它的表单控件添加显示异常信息的功能:
NameisrequiredMinimumof2charactersEmailisrequiredConfirmingemailisrequired
我们通过使用模板变量的方式,为account表单组添加了显示验证异常信息的功能。但有没有其它更好的方式呢?有没有办法去掉userEmail和userConfirm引用对象呢?答案是肯定的,具体示例如下:
Bothemailsarerequired