Angular入门-表单异步验证

同步校验没什么可说的,在做异步校验的时候着实吃了不少苦,百度搜出来几乎全是复制的同一份教程连编译都过不去。自己比着官网例子写一份又因为对Rxjs不熟悉干的磕磕绊绊,头发大把的掉。这里把代码贴出来,同时也记录一下遇到的知识点,以备回顾。
注:本文以响应式表单为基础。

FormBuilder

FormBuilder其实就是一个可以快速生成表单控件的工具,导入该类之后可以通过this.fb.group方法快速创建一个FormGroup,例如

export class ProfileEditorComponent {
  profileForm = this.fb.group({
    firstName: [''],
    lastName: [''],
    address: this.fb.group({
      street: [''],
      city: [''],
      state: [''],
      zip: ['']
    }),
  });
}

其中每一项都是一个FormControl,需要在html中使用formControlName属性将其与之绑定。每个控件名对应的值都是一个数组,数组由三个参数组成,例如

email: [null, [Validators.required, this.emailRegxValidator()], this.emailUniqueValidator()]

数组中第一项表示字段的默认值,null表示没有
数组第二项为一个数组,其中填写所需同步校验器的方法名,即不需要后台校验的校验方法
数组第三项仍为一个数组,其中填写所需异步校验器的方法名

Rxjs操作符

Angular其实就是Rxjs和TypeScript的大集合,如果对Rxjs操作符完全不理解的话基本上是开发不下去的,但是Rxjs上手难度还是很高的(至少对我个人是这样)。在深入浅出Rxjs一书中是这么描绘Rxjs学习曲线的
在这里插入图片描述
太多的操作符现在我也不是很清楚,简要记录一下异步校验所用到的。
pipe 这个还是相对好理解的,就是字面含义管道。pipe指令可以将一系列操作符串接起来。在管道中,上一个操作符流出的数据流会流入下一个操作符,就像流水一样。
map map的作用类似于执行一个函数操作,在map操作符中可以将元数据按照一定的逻辑进行转化,其实就是输入一个数据,然后调用一个函数得到运算之后的数据。
switchMap 这个操作符什么意思至今未懂,只知道他可以调用一个服务然后把数据传进去。

校验器

回过头来看一下表单校验的校验器。校验器共有两种,同步校验和异步校验,验证器函数接受一个control,然后返回一组错误对象(验证不通过)或 null(验证通过),当未返回任何内容时表示未开始校验
异步校验器要求返回Promise或Observable,同时返回的可观察对象必须是有限的,也就是说,它必须在某个时间点结束(complete)。要把无尽的可观察对象转换成有限的,可以使用 first、last、take 或 takeUntil 等过滤型管道对其进行处理。
验证错误是一个对象,对象结构唯一的要求是key必须为字符串,值可以为any类型,例如你可以返回一个{duplicate: true},表示当前control的duplicate校验未通过。
值得注意的是,出于性能考虑,异步校验器会在所有同步校验器完成之后才会触发,在此之前异步校验器会处于正确状态。
异步验证开始时,表单将进入Pending状态,当验证结果返回之后才会变成valid或invalid。在判断表单状态的时候需要注意一下异步问题。当判断为pending时进入一个定时器循环判断直到不为pending为止。

实例

有了上面的基础写一个异步校验器应该就没什么大问题了。不过http的防抖需要考虑进去,不然用户每输入一个字符就要触发一次后台校验成本太高了。

userNameUniqueValidator() {
  return (control: FormControl): any => {
    //进入管道进行串行操作
    //valueChanges表示字段值变更才触发操作
    return control.valueChanges.pipe(
      //同valueChanges,不写也可
      distinctUntilChanged(),
      //防抖时间,单位毫秒
      debounceTime(400),
      //调用服务,参数可写可不写,如果写的话变成如下形式
      //switchMap((val) => this.registerService.isUserNameExist(val))
      switchMap(() => this.registerService.isUserNameExist(control.value)),
      //对返回值进行处理,null表示正确,对象表示错误
      map(res => res.code == "200" ? null : {duplicate: true}),
      //每次验证的结果是唯一的,截断流
      first()
      );
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值