在上一个小节中实现了学号、姓名在后台的验证,当学号、姓名不符合设定规则上,无法更新成功。本小节在此基础上使用表单验证的方式提升编辑功能的用户使用感受。 # 介绍 表单验证是个常用的功能,angular的官方文档在基本原理一章中单独将其列为一节 ---- [表单验证](https://www.angular.cn/guide/form-validation),而且对模板驱动式表单及响应式表单的验证方式单独做了说明,编辑学生组件中使用的是`响应式表单`,本小节中将参考官方文档完成姓名、学号的验证。当姓名或学号不符合规则时给出友好的提示,且禁用保存按钮。 验证为前台的新知识点,故采用集成测试的方式进行学习。在正式学习以前,仍然按原测试步骤:启动数据库、后台、前台、添加模拟数据的顺序进行一些数据的准备工作。 ## 验证姓名 来到编辑学生界面: ![](https://img.kancloud.cn/8b/5b/8b5bef5e52049aa6a0b81fd6678eb828_838x133.png) ### minLength 姓名的最小长度为2,则添加一个最小长度的验证器: src/app/student/edit/edit.component.ts ```javascript ngOnInit() { ... this.formGroup = new FormGroup({ name: new FormControl('', ➊), sno: new FormControl('') }); } ``` * ➊ 在FormController的第二个参数中添加验证器。 angular内置了常用的验证器,此时添加最小长度验证器`minLength` src/app/student/edit/edit.component.ts ```javascript import {FormControl, FormGroup, Validators} from '@angular/forms'; ... ngOnInit() { ... this.formGroup = new FormGroup({ name: new FormControl('', Validators.minLength(2)➊), sno: new FormControl('') }); } ``` * ➊ 最小长度验证器,接收的参数为最小的长度值。`minLength(2)`表示最小的长度为2。 测试: src/app/student/edit/edit.component.html ``` <label>姓名:<input name="name" formControlName="name"/></label> <pre>{{formGroup.get('name').errors | json}}</pre> ✚ ➊ <label>学号:<input name="sno" formControlName="sno"/></label> ``` * ➊ 若验证失败,将显示在对应字段的error属性上 ![](https://img.kancloud.cn/4a/a4/4aa467e6993eec5abf3491787b57f499_530x334.gif) 观察发现: * ① 当name的值大于等于minLength设置值时,在字段name上的errors为null * ② 当name有值且小于minLength的设置值时,在字段name上显示对应的errors信息:minLength,该信息包括:设置的最小长度值、实际的长度值。 * ③ 当name无值时。minLength验证器不生效。 根据以上信息,打造友好的验证提醒如下: src/app/student/edit/edit.component.html ``` <button type="submit">保存</button> <div class="alert-warning" *ngIf="formGroup.get('name').errors"> ✚ ➊ <p>输入的姓名过短</p> ✚ </div> ✚ </form> ``` * ➊ 当name发生校验错误时,显示本警告框 测试: ![](https://img.kancloud.cn/96/1f/961f32d0bbdc667b3fa4a9c7635b6812_530x334.gif) ### maxLength maxLength及minLength的使用方法一致,除可以直接在FormControl上设置某个验证器外,FormControl还支持批量设置验证器。比如当前在name上再添加一个maxLength验证器: src/app/student/edit/edit.component.ts ```javascript ngOnInit() { ... this.formGroup = new FormGroup({ name: new FormControl('', [ // ➊ Validators.minLength(2), Validators.maxLength(10)]), // ➋ sno: new FormControl('') }); } ``` * ➊ FormControl的构造函数还支持第二个参数的类型为数组,在该数组中依次添加验证器。 * ➋ 使用 maxLength来指定姓名的最大长度为10 ![](https://img.kancloud.cn/05/1d/051dfb8cff4dc6611af2dfdb6cc1bf38_524x286.png) 有了多个验证器后,就需要对提示信息进行简单的处理了。 src/app/student/edit/edit.component.html ```html <div class="alert-warning" *ngIf="formGroup.get('name').errors"> <p *ngIf="formGroup.get('name').errors?.minlength">输入的姓名过短</p> <p *ngIf="formGroup.get('name').errors?.maxlength">输入的姓名过长</p> </div> </form> ``` * 加入`ngIf`来分别进行提示 ### requried 加入最短最长提示后的确友好了很多,但当`name`值为空时`minLength`验证器并没有报错。这便需要单独对name为空进行提醒。requried的验证方式有两种,第一种是最简单的在V层为`input`加入`requried`属性;第二种是加入和`minlength`相似的验证器。 src/app/student/edit/edit.component.html ``` <label>姓名:<input name="name" formControlName="name" required ➊/></label> ``` * ➊ 这是最普通的html表单的写法,该写法被所有的浏览器所识别,当使用`required`标记的`input`为空时,将无法进行表单的提交 ![](https://img.kancloud.cn/51/c5/51c58c425516eba9ec622efd5ec82afa_511x197.png) 定制错误信息如下: src/app/student/edit/edit.component.html ```html <div class="alert-warning" *ngIf="formGroup.get('name').errors"> <p *ngIf="formGroup.get('name').errors?.minlength">输入的姓名过短</p> <p *ngIf="formGroup.get('name').errors?.maxlength">输入的姓名过长</p> <p *ngIf="formGroup.get('name').errors?.required">姓名不能为空</p> ✚ </div> ``` 测试: ![](https://img.kancloud.cn/5a/ba/5abaa4112c5d43ba25ff25e876b94848_530x334.gif) 除了直接为input添加`required`外,还可以在使用添加`required`验证器的方式来达到验证某个字段的目的。 src/app/student/edit/edit.component.ts ```javascript this.formGroup = new FormGroup({ name: new FormControl('', [ Validators.minLength(2), Validators.maxLength(10), Validators.required]), ➊ ``` 此时删除V层`input`上的`required`也同样达到验证的效果。 src/app/student/edit/edit.component.html ```html <label>姓名:<input name="name" formControlName="name"/></label> ``` 测试效果与刚刚相同: ![](https://img.kancloud.cn/5a/ba/5abaa4112c5d43ba25ff25e876b94848_530x334.gif) 官方推荐的做法是即在C层中加入验证器以明确的展示该自动是要进行`required`验证的,又要在V层中添加required以使用浏览器默认的`required`验证。所以最后让我们恢复V层中刚刚删除的`required`。 src/app/student/edit/edit.component.html ```html <label>姓名:<input name="name" formControlName="name" required/></label> ``` ## 验证学号 学号的验证规则是:长度必须为6位。angular并没有固定长度验证器,但可以使用`minLength`结合 `maxLength`来解决该问题: src/app/student/edit/edit.component.ts ```javascript this.formGroup = new FormGroup({ name: new FormControl('', [ Validators.minLength(2), Validators.maxLength(10), Validators.required]), sno: new FormControl('', [ Validators.required, ✚ Validators.maxLength(6), ✚ Validators.minLength(6) ✚ ]) }); ``` * 将最小最大长度均设置为6,则只有当长度为6时才不会发生错误。同时规定`required`,以解决当学号为空`minLength`验证器失效的问题。 对应更新V层代码: src/app/student/edit/edit.component.html ```html <label>学号:<input name="sno" formControlName="sno" required ✚ /></label> ... <div class="alert-warning" *ngIf="formGroup.get('name').errors || formGroup.get('sno').errors"> ➊ <p *ngIf="formGroup.get('name').errors?.minlength">输入的姓名过短</p> <p *ngIf="formGroup.get('name').errors?.maxlength">输入的姓名过长</p> <p *ngIf="formGroup.get('name').errors?.required">姓名不能为空</p> <p *ngIf="formGroup.get('sno').errors">输入的学号格式不正确</p> ➋ </div> ``` * ➊ 使用`||`将`sno`字段报错添加到显示条件中 * ➋ 给出简单的提示信息 ![](https://img.kancloud.cn/35/a1/35a1be00f0682a859960ab7ce4299419_530x334.gif) # 验证失败禁用保存按钮 在angular中可以使用在按钮标签上添加`[disabled]="调用的方法或值"`来禁用某个按钮,比如: src/app/student/edit/edit.component.html ``` <button type="submit" [disabled]="true">保存</button> ``` ![](https://img.kancloud.cn/56/b4/56b48d215fdd0689a3a074878a067f6e_811x105.png) 还可以将`[disabled]="true"`换成表达式,然后对应在C层中返回false达到同样的效果: src/app/student/edit/edit.component.html ```html <button type="submit" [disabled]="disableSubmitButton()">保存</button> ``` src/app/student/edit/edit.component.ts ``` disableSubmitButton() { return true; } ``` 效果相同: ![](https://img.kancloud.cn/56/b4/56b48d215fdd0689a3a074878a067f6e_811x105.png) 接下来我们将formGroup传入该表达式,然后在该表达式中对姓名及学号字段是否发生错误进行判断,便可以达到当表单中的formControl验证失败时禁用保存按钮的目的。 src/app/student/edit/edit.component.html ```html <button type="submit" [disabled]="disableSubmitButton(fromGroup)➊">保存</button> ``` * ➊ 将要验证的formGroup由此传入 src/app/student/edit/edit.component.ts ```javascript /** * 是否禁用保存按钮 * 当姓名或学号任意字段验证失败时,均返回true * @param formGroup 表单组 * @return true 禁用按钮;false 启用按钮 */ disableSubmitButton(formGroup: FormGroup): boolean { if (formGroup.get('name').errors !== null) { return true; } if (formGroup.get('sno').errors !== null) { return true; } return false; } ``` 测试如下: ![](https://img.kancloud.cn/3b/e5/3be5ca5ca48266b97df8349124ca51c8_1277x270.gif) 此外该方法还只可以简写为: ```javascript disableSubmitButton(formGroup: FormGroup): boolean { if (formGroup.get('name').errors !== null || formGroup.get('sno').errors !== null) { return true; } return false; } ``` 再进一步简写为: ```javascript disableSubmitButton(formGroup: FormGroup): boolean { return formGroup.get('name').errors !== null || formGroup.get('sno').errors !== null; } ``` # 参考文档 | 名称 | 链接 | 预计学习时长(分) | | --- | --- | --- | | 源码地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.7.10](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step4.7.10) | - | | FormControl | [https://angular.cn/api/forms/FormControl](https://angular.cn/api/forms/FormControl) | 5 | | 表单验证 | [https://www.angular.cn/guide/form-validation#form-validation](https://www.angular.cn/guide/form-validation#form-validation) | 15 |