为什么我要在这个验证器上"Cannot read property 'http' of undefined"?



我正在尝试为响应式表单控件制作一个异步验证器,用于检查给定的用户名是否已经存在。这是异步验证器代码:

userdata.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class UserdataService {
private apiUrl = 'http://apiurl.com/api'; // its not the real url, im just not posting it for privacy reasons
constructor(private http: HttpClient) {}

checkUsername(control: FormControl): Promise<any> | Observable<any> {
let isUsernameValid;
return new Promise<any>(
(resolve, reject) => {
this.http.get(this.apiUrl + '/users?name='+control.value).subscribe(
response => {
isUsernameValid = response;
});
if (isUsernameValid === 'false') {
resolve({'usernameIsInvalid': true})
} else {
resolve(null);
}
}
);
}
}

当我尝试此验证器时,我会收到以下错误:"core.js:4197错误类型错误:无法读取未定义"的属性"http";

现在,我认为errr与使用"this"有关,但我不明白为什么不起作用。。。这让我发疯了,所以我试着放一个

console.log(this.apiUrl)

在函数内部,在承诺之外,只是为了尝试,我也犯了同样的错误:"core.js:4197错误类型错误:无法读取未定义的属性"apiUrl";。。。

如果有人能向我解释我做错了什么,以及如何解决,我将不胜感激。

编辑:

我从被动表单ts文件调用我的服务,如下所示:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { CustomValidatorsService } from '../services/custom-validators.service';
import { LocationService } from '../services/location.service';
import { UserdataService } from '../services/userdata.service';
@Component({
selector: 'app-userdata-form',
templateUrl: './userdata-form.component.html',
styleUrls: ['./userdata-form.component.scss']
})
export class UserdataFormComponent implements OnInit {
userdataForm: FormGroup;
provinces: any = null;
provincesLoading = false;
cities: any = null;
citiesLoading = false;
constructor(
private locationService: LocationService,
private userdataService: UserdataService,
private customValidators: CustomValidatorsService,
private router: Router,
private route: ActivatedRoute
) { }
ngOnInit(): void {
this.formInit();
this.loadProvinces();
}
formInit() {
let dni: number = null;
let firstname: string = null;
let lastname: string = null;
let email: string = null;
let mobile: number = null;
let phone: number = null;
let birthdate: Date = null;
let username: string = null;
let password: string = null;
this.userdataForm = new FormGroup({
// ... a lot of controls before ...
'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿu00f1u00d1]+(s*[a-zA-ZÀ-ÿu00f1u00d1]*)*[a-zA-ZÀ-ÿu00f1u00d1]+$/)
], this.userdataService.checkUsername), // <-- here's the async validator
// ... form continues...
}
loadProvinces() {
this.provincesLoading = true;
this.locationService.getProvinces().subscribe(response => {
this.provinces = response;
this.provincesLoading = false;
});
}

正如我在评论中提到的,您的自定义验证器应该实现AsyncValidator接口:

import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
import { catchError, map } from 'rxjs/operators';
// ...
@Injectable({
providedIn: 'root'
})
export class UserDataValidator implements AsyncValidator {
private apiUrl = 'http://apiurl.com/api'; // its not the real url, im just not posting it for privacy reasons
constructor(private http: HttpClient) {}
// This method is defined as an arrow function such that it can be used
// properly - see https://github.com/angular/angular/issues/24981
validate = (control: AbstractControl) => {
return this.http.get(`${this.apiUrl}/users?name=${control.value}`).pipe(
map(isUsernameValid => (isUsernameValid === 'false' ? { usernameIsInvalid: true } : null),
catchError(() => of(null))
);
}
}

然后可以将其添加到您的FormGroup中,如下所示:

constructor (private userDataValidator: UserDataValidator) {
this.userdataForm = new FormGroup({
username: new FormControl(username, [
// ... validators
// Validator classes don't currently work - see
// https://github.com/angular/angular/issues/24981
this.userDataValidator.validate
]),
// ... other form controls
}
// ...

注释

  • 我还清理了执行验证逻辑的代码,以使用RxJS的可管道运算符以及模板文字(
  • 免责声明:我还没有测试过上面的代码是否真的有效

资源

  • 角度-验证表单输入>创建异步验证器
  • 允许将验证器类传递给FormControl构造函数·Issue#24981·angular/angular

我认为你应该创建一个验证器函数,它在参数中获取服务实例,就像本文中一样:https://medium.com/@tomaszssochacki/如何操作-角式同步验证器-7-6e80243a874a

当你通过这种方法时

'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿu00f1u00d1]+(s*[a-zA-ZÀ-ÿu00f1u00d1]*)*[a-zA-ZÀ-ÿu00f1u00d1]+$/)
], this.userdataService.checkUsername),

checkUsername方法中的this上下文丢失

或者你可以这样做:

'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿu00f1u00d1]+(s*[a-zA-ZÀ-ÿu00f1u00d1]*)*[a-zA-ZÀ-ÿu00f1u00d1]+$/)
], this.userdataService.checkUsername.bind(this.userdataService)),

当调用时,第一个参数中的bind将"this"上下文传递给方法

相关内容

最新更新