大家在日常生活中,应该看过满多表单的某个栏位会随着另个栏位的改变,而造成该栏位的验证逻辑需要改变的情况吧?
举例来说,可能会有个栏位叫做联络资讯,使用者可以选择要填入手机号码或者是 E-mail ,该栏位再根据使用所选择的类型来检核该栏位的值。
今天,我们就来用 Reactive Forms 实作这个栏位,而这个栏位我会实作在我们的被保人表单上,各位就随意吧!
如果已经忘记被保人表单长怎麽样的话,可以先回头复习一下第十一天的文章:Reactive Forms 实作 - 动态表单初体验。
首先,我们需要在原本的被保人表单里新增一个栏位:联络资讯。
HTML 的部份大概会长这样:
<p>
<label>联络资讯:</label>
</p>
<p>
<select>
<option value="">请选择</option>
<option value="mobile">手机</option>
<option value="email">E-Mail</option>
</select>
<input type="text">
</p>
画面看起来会像这样:
虽然联络资讯是一个栏位,但其实我们需要两个 FormControl
,一个给下拉选单,一个给实际填值的 input
元素。
因此,我们要在原本的 createInsuredFormGroup
里多加两个栏位,像是这样:
private createInsuredFormGroup(): FormGroup {
return this.formBuilder.group({
name: [
'',
[Validators.required, Validators.minLength(2), Validators.maxLength(10)]
],
gender: ['', Validators.required],
age: ['', Validators.required],
contactInfoType: ['', Validators.required],
contactInfo: ['', Validators.required]
});
}
然後将刚刚新增的栏位与画面的元素绑定:
<p>
<select formControlName="contactInfoType">
<option value="">请选择</option>
<option value="mobile">手机</option>
<option value="email">E-Mail</option>
</select>
<input type="text" formControlName="contactInfo">
</p>
接着我们透过把资料印在画面上的方式来检查是否已正确绑定,像这样:
<pre>{{ formGroup?.getRawValue() | json }}</pre>
结果:
看起来已经有正确跟画面上的元素绑定了,那接下来要怎麽做才好呢?
FormControl 的父类别 AbstractControl 有个属性叫做 valueChanges ,它是一个 Observable 。
我们可以透过订阅某个 AbstractControl 的 valueChanges 这个 Observable 来知道该栏位是否已经发生变化,并且做出相应的处理。
因此,我们可以这样调整 createInsuredFormGroup
里的实作:
private createInsuredFormGroup(): FormGroup {
const contactInfoTypeControl = this.formBuilder.control('', Validators.required);
const contactInfoControl = this.formBuilder.control('', Validators.required);
contactInfoTypeControl.valueChanges.subscribe((value) => {
switch (value) {
case 'mobile':
contactInfoControl.setValidators([Validators.required, Validators.pattern(/^09\d{8}$/)]);
break;
case 'email':
contactInfoControl.setValidators([Validators.required, Validators.email]);
break;
default:
contactInfoControl.setValidators([Validators.required]);
break;
}
contactInfoControl.updateValueAndValidity();
});
return this.formBuilder.group({
name: [
'',
[Validators.required, Validators.minLength(2), Validators.maxLength(10)]
],
gender: ['', Validators.required],
age: ['', Validators.required],
contactInfoType: contactInfoTypeControl,
contactInfo: contactInfoControl
});
}
上述程序码中有以下三个要点:
建立 FormControl
的时候可以藉由 this.formBuilder.control()
的方式建立,也可以直接使用 new FormControl()
建立,这点在前面的文章已经有提过,不过我在这边再提醒大家一次。
setValidators()
执行完後,记得一定要使用 updateValueAndValidity()
来更新当前栏位的验证,不然就要等到该栏位的值有改变时才会以新的验证器来验证。
由於 contactInfoType
允许使用者选择 请选择
的选项,因此记得在 default
的区块里,将 Validators.required
给加回去。
这边改好之後,我们也顺便调整一下 getErrorMessage
的实作,让使用者可以知道该栏位的验证有误:
getErrorMessage(key: string, index: number): string {
const formGroup = this.formArray.controls[index];
const formControl = formGroup.get(key);
let errorMessage: string;
if (!formControl || !formControl.errors || formControl.pristine) {
errorMessage = '';
} else if (formControl.errors.required) {
errorMessage = '此栏位必填';
} else if (formControl.errors.minlength) {
errorMessage = '姓名至少需两个字以上';
} else if (formControl.errors.maxlength) {
errorMessage = '姓名至多只能输入十个字';
// 增加以下两个判断
} else if (formControl.errors.pattern) {
errorMessage = '手机号码格式错误';
} else if (formControl.errors.email) {
errorMessage = 'E-mail 格式错误';
}
return errorMessage!;
}
这边要提醒大家的是,由於验证 E-mail 格式的方式我今天是用 Validators.email
的验证器来验,不是之前的 Validators.pattern()
,所以我可以直接用 formControl.errors.email
来判断。
如果实作时,手机号码跟 E-mail 都是用 Validators.pattern()
的验证器来验的话,就需要进一步去比对 formControl.errors.pattern
里的 Regular Expression 来分辨究竟是手机号码的格式错误还是 E-mail 的格式错误了。
像是这样:
} else if (formControl.errors.pattern) {
const requiredPattern = formControl.errors.pattern.requiredPattern;
if (requiredPattern === '/A Regular Expression/') {
errorMessage = '手机号码格式错误';
} else if (requiredPattern === '/B Regular Expression/') {
errorMessage = 'E-mail 格式错误';
}
}
如此一来,我们就完成这个栏位的功能罗!
结果:
今天的重点是学会如何使用 valueChanges 来动态调整相关栏位的验证逻辑。
虽然是 Observable 是 RxJS 的东西,但今天并没有太艰难或太复杂的运用,使用上的感觉会跟使用 Promise 的感觉类似,不过我个人认为 RxJS 好玩且强大许多。
关於 RxJS ,如果大家想知道更多资讯,我推荐大家去看 Mike 的打通 RxJS 任督二脉系列文,或者是直接买实体书也行。
虽然今天的实作已经完成了,但因为有调整程序码的关系,测试程序码其实也需要相应的调整才不会出错,此部份就交给大家实作我就不再用篇幅分享实作罗!
今天的程序码会放在 Github - Branch: day23 上供大家参考,建议大家在看我的实作之前,先按照需求规格自己做一遍,之後再跟我的对照,看看自己的实作跟我的实作不同的地方在哪里、有什麽好处与坏处,如此反覆咀嚼消化後,我相信你一定可以进步地非常快!
如果有任何的问题或是回馈,还请麻烦留言给我让我知道!
>>: Day26 vue.js功能展示ep2之有"大麻"烦(cros跨域)
嗨各位好久不见, 今天要来分享上次的续集 第 2 part , 上篇讲到建构器 今天要来分享关於继...
Day 3 Capsule Network 前言 昨天讲到CNN的限制,那今天就要开始介绍甚麽是胶囊...
底下为一些资源 JavaScript 标准参考教程(alpha) ECMAScript 6 入门 现...
未来社会中,文盲并非不识字的人,而是不能再学习的人。铁人赛就是强迫自己学习的好机会。 大家好今天我要...
今天我们会把Route 53串接到昨天建置的ELB上。但开始之前,我们先问自己一个问题,Route ...