Web
开发中,表单一直是一个重要的话题。html
在AngularJS
中,咱们可使用双向数据绑定很简单地完成表单的开发,可是会带来严重的性能问题,而Angular
对于表单的设计,让咱们的表单在保持性能的同时更优雅。程序员
咱们以一个最简单的登陆表单为例来学习Angular
中的表单:typescript
这就是Angular
的表单思想,一个FormGroup
管理整个表单,同时FormControl
管理表单内的各个元素。小程序
导入表单模块:api
基础的HTML
表单代码:框架
<div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h2 class="text-center">Angular Form</h2> <form> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" placeholder="Email" /> </div> <div class="form-group"> <label>Password</label> <input type="password" class="form-control"placeholder="Password" /> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> </div> </div>
略加修改:函数
<div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-4"> <h2 class="text-center">Angular Form</h2> <form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" placeholder="Email" ngModel /> </div> <div class="form-group"> <label>Password</label> <input type="password" class="form-control"placeholder="Password" ngModel /> </div> <button type="submit" class="btn btn-default">Submit</button> </form> </div> </div> </div>
当咱们的应用导入FormsModule
时,form
就再也不是原生的form
了,而是Angular
重写过的NgForm
组件,就像在AngularJS
中使用的form
实际上是被框架扩展的指令。性能
因此咱们能够为form
添加NgForm
组件定义的输入输出。学习
这是NgForm
的官方api
文档描述,导出ngForm
,而后输出ngSubmit
事件。测试
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)"> </form>
这里用到了导出的ngForm
,并为其取名为myForm
,因此传给onSubmit
的myForm
其实就是导出的ngForm
,当业务逻辑很是简单的状况下能够这样写,直接用导出的ngForm
,就至关于使用一个默认配置好的对象。
<input type="email" class="form-control" name="email" placeholder="Email" ngModel /> <input type="password" class="form-control" name="password" placeholder="Password" ngModel />
两个input
用到了ngModel
指令,该指令会为该元素建立一个默认的FormControl
。
onSubmit(myForm: NgForm): void { console.log(myForm); console.log(myForm.value); }
提交表单,打印,能够查看myForm
中的许多属性,同时它的value
属性就是表单内容。
点开NgForm
,其实除了表单的值外,还有dirty
、error
、invalid
等属性方便咱们对表单进行验证。
点开controls
属性,咱们能够看到该表单中的FormControl
:
<input type="email" class="form-control" name="email" placeholder="Email" /> <input type="password" class="form-control" name="password" placeholder="Password" />
咱们尝试将input
中原来添加的ngModel
指令删除,再打印。能够看到该表单中没有FormControl
。
这就验证了咱们以前的猜测,ngModel
指令默认的单向数据绑定,其实就是为咱们建立了一个默认的FormControl
用于控制该元素的值。
在不考虑表单验证的前提下,这个基本的新增表单应该就算完成了,在onSubmit
中获取表单的值,而后包装对象调用Service
请求api
。
新增时由于没有初始的数据,因此直接使用默认建立的FormGroup
和FormControl
就好了,可是编辑时是有初始化的数据的,因此咱们就须要建立自定义的FormGroup
、FormControl
。
这里是Angular权威指南
中推荐初始化表单的方式,固然也能够去new
。
仍是规范,构造和初始化分开,constructor
中使用formBuilder
构造FormGroup
、FormControl
。
myForm: FormGroup; constructor(formBuilder: FormBuilder) { this.myForm = formBuilder.group({ email: '', password: '' }); }
初始化,为FormControl
设置数据,实际开发应该是从后台获取数据而后设置,这里为了演示方便,直接setValue
。
ngOnInit() { this.getOriginData(); } getOriginData(): void { this.myForm.setValue({ email: 'zhangxishuo1998@gmail.com', password: 'this is password' }); }
数据有了,接下来就是将数据绑定到组件上。将myForm
做为参数传给组件,ngSubmit
不变。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" name="email" placeholder="Email" [formControl]="myForm.controls['email']" /> </div> <div class="form-group"> <label>Password</label> <input type="text" class="form-control" name="password" placeholder="Password" [formControl]="myForm.controls['password']" /> </div> <button type="submit" class="btn btn-default">Submit</button> </form>
绑定成功!
修改代码,咱们删除邮箱与密码的初始化代码,让其为默认的空值。
纵使风云变幻,始终不离其宗。
<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)"> <div class="form-group"> <label>Email address</label> <input type="email" class="form-control" name="email" placeholder="Email" [formControl]="myForm.controls['email']" /> </div> <pre>Valid: {{ myForm.controls['email'].valid }}</pre> <pre>Touch: {{ myForm.controls['email'].touched }}</pre> <div class="form-group"> <label>Password</label> <input type="text" class="form-control" name="password" placeholder="Password" [formControl]="myForm.controls['password']" /> </div> <pre>Valid: {{ myForm.controls['password'].valid }}</pre> <pre>Touch: {{ myForm.controls['password'].touched }}</pre> <button type="submit" class="btn btn-default">Submit</button> </form>
咱们想对这两个输入框进行验证,直接在初始化时设置验证条件:
constructor(formBuilder: FormBuilder) { this.myForm = formBuilder.group({ email: ['', Validators.compose([ Validators.required, Validators.email ])], password: ['', Validators.required] }); }
实现验证:邮箱的空验证与邮箱格式验证,密码的空验证。
而后符合咱们以往的开发规范,用一个ngIf
的p
标签,而后当不合法且触碰过期,显示提示信息。
在以往的AngularJS
项目里,咱们只能用已有的验证规则,可是如今更强大了!
其实,咱们上面用到的required
、email
等的验证规则都是框架为咱们提供的已有的验证函数,翻开ValidatorFn - Angular,有ValidatorFn
接口,实现该接口,便可实现自定义的验证方法!
双向数据绑定的思考:
既然表单都设计得如此强大,咱们又何须拘于双向数据绑定,双向数据绑定是咱们实现软件功能的一种方式,但不是惟一方式。
若是使用双向数据绑定,那确定比我上面说的简单许多,可是自从学习了软件测试,渐渐明白了,其实咱们在作软件开发时,与咱们日常在学校写代码是不同的。
就像今天吴老师讲的例子:求e
的50
次方。若是在学校,咱们可能直接一个for
循环50
次而后一次一次去乘。
可是若是在公司,咱们可能就会先算e的平方
,而后再算出e的四次方
,e的八次方
,而后根据几个已有的去组合须要的结果,这会让性能大幅提高。
这是美团点评团队优化小程序的一篇博客:
或许,以前的咱们学习了不少知识,学会了很多框架,也写过许多代码,可是我对本身的评价仍是程序员。今天,我才明白,何为软件工程师?!
立个小目标:之后写代码时多考虑一点,优秀的软件工程师写出的代码是可以直接上线的。