Angular自定义表单验证器报错:Cannot read properties of undefined (reading 'found')
Angular自定义表单验证器修复与实现
问题
提交表单调用API后,需根据返回结果设置notExisted为true时显示“Not found”错误提示,但提交后控制台抛出TypeError: Cannot read properties of undefined (reading 'found')(编译后变量名映射导致显示为found,实际为读取notExisted相关属性失败)。
报错信息
ERROR Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'found') TypeError: Cannot read properties of undefined (reading 'found') at src_app_main_pages_pages_module_ts.js:906:27 at new ZoneAwarePromise (polyfills.js:10389:21) at push.9650.AuthForgotPasswordV2Component.existValidator (src_app_main_pages_pages_module_ts.js:904:16) at vendor.js:76993:12 at Array.map (<anonymous>) at executeValidators (vendor.js:76992:21) at FormControl._composedValidatorFn (vendor.js:77023:24) at FormControl._runValidator (vendor.js:78668:36) at FormControl.updateValueAndValidity (vendor.js:78631:28) at FormControl.setValue (vendor.js:79115:12) at resolvePromise (polyfills.js:10309:19) at new ZoneAwarePromise (polyfills.js:10391:9) at push.9650.AuthForgotPasswordV2Component.existValidator (src_app_main_pages_pages_module_ts.js:904:16) at vendor.js:76993:12 at Array.map (<anonymous>) at executeValidators (vendor.js:76992:21) at FormControl._composedValidatorFn (vendor.js:77023:24) at FormControl._runValidator (vendor.js:78668:36) at FormControl.updateValueAndValidity (vendor.js:78631:28) at FormControl.setValue (vendor.js:79115:12)
现有代码
组件代码
public public notExisted = true; get f() { return this.forgotPasswordForm.controls; } //API onSubmit() { this.submitted = true; // stop here if form is invalid if (this.forgotPasswordForm.invalid) { return; } this._authenticationService.forgotPassword(this.f.email.value) .subscribe( (data) => { console.log(data.statusCode) if (data.statusCode == 200 || data.statusCode == '200') { this.notExisted = false; this.sended = true; } else if (data.statusCode == 204 || data.statusCode == '204') { this.notExisted = true; this.sended = false; this.error = data.content;; } else { this.notExisted = false; this.sended = false this.error = data.content; } } } //custom validator existValidator(control: FormControl) { return new Promise((resolve, reject) => { if (this.notExisted !== undefined) { if (this.notExisted == true) { resolve({ notExisted: true }); } else { resolve(null); } } else { resolve(null); } }); } ngOnInit(): void { console.log(this.currentDate); this.forgotPasswordForm = this._formBuilder.group({ email: ['', [Validators.required, Validators.email,this.existValidator]] }); // Subscribe to config changes this._coreConfigService.config.pipe(takeUntil(this._unsubscribeAll)).subscribe(config => { this.coreConfig = config; }); }
HTML代码
<form class="auth-forgot-password-form mt-2" [formGroup]="forgotPasswordForm" (ngSubmit)="onSubmit()"> <div class="form-group"> <label class="form-label" for="forgot-password-email">Email</label> <input class="form-control" type="text" formControlName="email" placeholder="john@example.com" aria-describedby="forgot-password-email" autofocus="" tabindex="1" [ngClass]="{ 'is-invalid': submitted && f.email.errors}" /> <div *ngIf="submitted && f.email.errors" class="invalid-feedback"> <div *ngIf="f.email.errors.required">Email is required</div> <div *ngIf="f.email.errors.email">Email must be a valid email address</div> <div *ngIf="f.email.errors.notExisted">Not found</div> </div> </div> <button class="btn btn-primary btn-block" tabindex="2" rippleEffect>Send reset link</button> </form>
修复方案
核心问题分析
this指向丢失:验证器函数作为参数传递给FormControl时,函数内部的this不再指向组件实例,导致无法读取this.notExisted。- 验证时机错误:原验证器会在表单值变化时自动执行,初始
notExisted=true会导致页面加载时就显示错误,不符合“提交后根据API结果显示”的需求。
修改后的完整代码
组件代码
public notExisted = false; // 初始设为false,避免未提交就显示错误 public submitted = false; public sended = false; public error = ''; get f() { return this.forgotPasswordForm.controls; } // API提交逻辑 onSubmit() { this.submitted = true; this.error = ''; if (this.forgotPasswordForm.invalid) { return; } this._authenticationService.forgotPassword(this.f.email.value) .subscribe( (data) => { console.log(data.statusCode); if (data.statusCode == 200 || data.statusCode == '200') { this.notExisted = false; this.sended = true; } else if (data.statusCode == 204 || data.statusCode == '204') { this.notExisted = true; this.sended = false; this.error = data.content; } else { this.notExisted = false; this.sended = false; this.error = data.content; } // API返回后手动触发表单验证,更新错误状态 this.f.email.updateValueAndValidity({ emitEvent: false }); }, (err) => { // 处理API请求失败情况 this.notExisted = false; this.sended = false; this.error = 'Request failed'; this.f.email.updateValueAndValidity({ emitEvent: false }); } ); } // 自定义验证器:改为箭头函数,保留this指向 existValidator = (control: FormControl) => { return new Promise((resolve) => { // 仅在表单提交后,根据notExisted判断是否返回错误 if (this.submitted && this.notExisted) { resolve({ notExisted: true }); } else { resolve(null); } }); } ngOnInit(): void { console.log(this.currentDate); this.forgotPasswordForm = this._formBuilder.group({ email: ['', [Validators.required, Validators.email, this.existValidator]] }); this._coreConfigService.config.pipe(takeUntil(this._unsubscribeAll)).subscribe(config => { this.coreConfig = config; }); }
HTML代码(无需修改)
<form class="auth-forgot-password-form mt-2" [formGroup]="forgotPasswordForm" (ngSubmit)="onSubmit()"> <div class="form-group"> <label class="form-label" for="forgot-password-email">Email</label> <input class="form-control" type="text" formControlName="email" placeholder="john@example.com" aria-describedby="forgot-password-email" autofocus="" tabindex="1" [ngClass]="{ 'is-invalid': submitted && f.email.errors}" /> <div *ngIf="submitted && f.email.errors" class="invalid-feedback"> <div *ngIf="f.email.errors.required">Email is required</div> <div *ngIf="f.email.errors.email">Email must be a valid email address</div> <div *ngIf="f.email.errors.notExisted">Not found</div> </div> </div> <button class="btn btn-primary btn-block" tabindex="2" rippleEffect>Send reset link</button> </form>
关键修改说明
this指向修复:将existValidator改为箭头函数,确保函数内部的this始终指向组件实例,解决Cannot read properties of undefined错误。- 初始值调整:将
notExisted初始值设为false,避免页面加载时就显示“Not found”错误。 - 手动触发验证:在API请求完成后调用
updateValueAndValidity({ emitEvent: false }),触发验证器更新表单错误状态,同时emitEvent: false避免触发值变化的循环事件。 - 验证逻辑优化:验证器中增加
this.submitted判断,仅在表单提交后才根据notExisted返回错误,符合业务需求。
内容的提问来源于stack exchange,提问作者LHP1999
相关产品推荐
相关产品推荐

