Angular中如何用RxJS操作符而非订阅处理Observable状态设置表单验证?
Angular响应式表单:用RxJS map操作符设置验证器不生效的问题
我想基于RxJS BehaviorSubject的状态,用map操作符替代直接订阅的方式给Angular响应式表单设置验证器,但下面的代码完全没效果:
this.form_type$.pipe( map((type) => { if (type === 'signup') { this.auth_form ?.get('email') ?.setValidators([Validators.required, Validators.email]); this.auth_form ?.get('password') ?.setValidators([ Validators.required, Validators.minLength(8), Validators.pattern( `^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()|:;'"><,./?_=+-]).{8,}$` ), ]); } else { this.auth_form?.get('email')?.setValidators([]); this.auth_form?.get('password')?.setValidators([]); } }) );
但如果直接订阅BehaviorSubject,代码就能正常工作:
this.form_type$.subscribe((type) => { if (type === 'signup') { this.auth_form ?.get('email') ?.setValidators([Validators.required, Validators.email]); this.auth_form ?.get('password') ?.setValidators([ Validators.required, Validators.minLength(8), Validators.pattern( `^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()|:;'"><,./?_=+-]).{8,}$` ), ]); } else { this.auth_form?.get('email')?.setValidators([]); this.auth_form?.get('password')?.setValidators([]); } });
问题根源
- Observable的惰性执行:RxJS里的Observable是惰性的,只有调用
subscribe()之后,管道内的操作才会触发执行。你用pipe(map(...))只是构建了处理流程,但没有订阅,所以里面的代码根本不会运行。 - map操作符的用途错误:
map是用来转换数据流的纯函数,它应该返回新值,而不是执行设置验证器这类副作用操作。执行副作用应该用tap操作符。
修正方案
把map换成tap,然后订阅这个Observable(必须订阅,否则逻辑还是不会触发):
this.form_type$.pipe( tap((type) => { if (type === 'signup') { this.auth_form?.get('email')?.setValidators([Validators.required, Validators.email]); this.auth_form?.get('password')?.setValidators([ Validators.required, Validators.minLength(8), Validators.pattern(`^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()|:;'"><,./?_=+-]).{8,}$`) ]); } else { this.auth_form?.get('email')?.setValidators([]); this.auth_form?.get('password')?.setValidators([]); } // 设置验证器后更新控件状态,避免验证不生效 this.auth_form?.get('email')?.updateValueAndValidity({ emitEvent: false }); this.auth_form?.get('password')?.updateValueAndValidity({ emitEvent: false }); }) ).subscribe();
补充:设置完验证器后调用updateValueAndValidity()可以立即更新控件的验证状态,{ emitEvent: false }能避免触发不必要的表单值变更事件。
内容的提问来源于stack exchange,提问作者syahiruddin
相关产品推荐
相关产品推荐

