Angular 表单自定义验证器 http observable 在 http 调用时返回 null
Angular Form custom validator http observable returning null on http call
我正在尝试设置一个表单域来检查电子邮件是否存在。我查看了几个示例并进行了验证,但是当我实现 http 管道时,映射到我的服务的 Observable,它会将其作为 null 抛出?我可以假设我从我的服务中错误地管道到它,但我不太确定。
有人能帮我吗?
core.js:6014 ERROR TypeError: Cannot read property 'emailService' of undefined
app.component.ts
export class AppComponent implements OnInit {
signUpForm: FormGroup;
constructor(private fb: FormBuilder, private emailService: EmailService) { }
ngOnInit() {
this.signUpForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required], [this.validateEmailNotTaken]]
});
}
//Validator for checking if email name is taken or not
validateEmailNotTaken(control: AbstractControl): Observable<{ [key: string]: any } | null> {
if (control.value === null || control.value.length === 0) {
return of(null);
}
else {
return timer(1000).pipe(
switchMap(() => {
this.emailService.checkEmailExists(control.value).pipe(
map(res => {
//Do what with response
console.log(res);
if (!res) {
return { taken: true };
}
return of(null);
})
);
})
);
}
}
}
email.service.ts
interface IServerCheckEmailExists {
"available": boolean;
}
export interface ICheckEmailExists {
taken: boolean;
}
@Injectable({ providedIn: 'root' })
export class EmailService {
constructor(private _http: HttpClient) {
}
checkEmailExists(email: string): Observable<ICheckEmailExists[]> {
var postObject = {"action": "checkEmailExists"};
return this._http.post<IServerCheckEmailExists[]>("myapiurl/" + email, postObject).pipe(
map(o => o.map((sp): ICheckEmailExists => ({
taken: sp.available
})))
);
}
}
您的 validateEmailNotTaken 方法没有获取组件的实例。您需要在创建 formGroup 时绑定它。像这样修改您的代码:-
this.signUpForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required], [this.validateEmailNotTaken.bind(this)]]
});
请试试这个并告诉我。
我在您的代码中看到的唯一问题是您没有在 switchMap
中返回对 this.emailService.checkEmailExists(control.value)
的调用,因为您使用的是 {}
,所以您应该这样做.像这样:
import { Component, OnInit } from "@angular/core";
import {
FormGroup,
FormBuilder,
Validators,
AbstractControl
} from "@angular/forms";
import { Observable, of, timer } from "rxjs";
import { switchMap, map } from "rxjs/operators";
import { EmailService } from "./email.service";
@Component({
selector: "my-app",
templateUrl: `./app.component.html`,
styleUrls: [`./app.component.css`]
})
export class AppComponent implements OnInit {
signUpForm: FormGroup;
constructor(private fb: FormBuilder, private emailService: EmailService) {}
ngOnInit() {
this.signUpForm = this.fb.group({
name: ["", Validators.required],
email: ["", [Validators.required], [this.validateEmailNotTaken.bind(this)]]
});
}
//Validator for checking if email name is taken or not
validateEmailNotTaken(
control: AbstractControl
): Observable<{ [key: string]: any } | null> {
if (control.value === null || control.value.length === 0) {
return of(null);
} else {
return timer(1000).pipe(
switchMap(() => {
// RIGHT HERE
return this.emailService.checkEmailExists(control.value).pipe(
map(res => {
//Do what with response
console.log(res);
if (res) {
return of(null);
}
return { taken: true };
})
);
})
);
}
}
}
Here's a Working Code Example for your ref.
我正在尝试设置一个表单域来检查电子邮件是否存在。我查看了几个示例并进行了验证,但是当我实现 http 管道时,映射到我的服务的 Observable,它会将其作为 null 抛出?我可以假设我从我的服务中错误地管道到它,但我不太确定。
有人能帮我吗?
core.js:6014 ERROR TypeError: Cannot read property 'emailService' of undefined
app.component.ts
export class AppComponent implements OnInit {
signUpForm: FormGroup;
constructor(private fb: FormBuilder, private emailService: EmailService) { }
ngOnInit() {
this.signUpForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required], [this.validateEmailNotTaken]]
});
}
//Validator for checking if email name is taken or not
validateEmailNotTaken(control: AbstractControl): Observable<{ [key: string]: any } | null> {
if (control.value === null || control.value.length === 0) {
return of(null);
}
else {
return timer(1000).pipe(
switchMap(() => {
this.emailService.checkEmailExists(control.value).pipe(
map(res => {
//Do what with response
console.log(res);
if (!res) {
return { taken: true };
}
return of(null);
})
);
})
);
}
}
}
email.service.ts
interface IServerCheckEmailExists {
"available": boolean;
}
export interface ICheckEmailExists {
taken: boolean;
}
@Injectable({ providedIn: 'root' })
export class EmailService {
constructor(private _http: HttpClient) {
}
checkEmailExists(email: string): Observable<ICheckEmailExists[]> {
var postObject = {"action": "checkEmailExists"};
return this._http.post<IServerCheckEmailExists[]>("myapiurl/" + email, postObject).pipe(
map(o => o.map((sp): ICheckEmailExists => ({
taken: sp.available
})))
);
}
}
您的 validateEmailNotTaken 方法没有获取组件的实例。您需要在创建 formGroup 时绑定它。像这样修改您的代码:-
this.signUpForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required], [this.validateEmailNotTaken.bind(this)]]
});
请试试这个并告诉我。
我在您的代码中看到的唯一问题是您没有在 switchMap
中返回对 this.emailService.checkEmailExists(control.value)
的调用,因为您使用的是 {}
,所以您应该这样做.像这样:
import { Component, OnInit } from "@angular/core";
import {
FormGroup,
FormBuilder,
Validators,
AbstractControl
} from "@angular/forms";
import { Observable, of, timer } from "rxjs";
import { switchMap, map } from "rxjs/operators";
import { EmailService } from "./email.service";
@Component({
selector: "my-app",
templateUrl: `./app.component.html`,
styleUrls: [`./app.component.css`]
})
export class AppComponent implements OnInit {
signUpForm: FormGroup;
constructor(private fb: FormBuilder, private emailService: EmailService) {}
ngOnInit() {
this.signUpForm = this.fb.group({
name: ["", Validators.required],
email: ["", [Validators.required], [this.validateEmailNotTaken.bind(this)]]
});
}
//Validator for checking if email name is taken or not
validateEmailNotTaken(
control: AbstractControl
): Observable<{ [key: string]: any } | null> {
if (control.value === null || control.value.length === 0) {
return of(null);
} else {
return timer(1000).pipe(
switchMap(() => {
// RIGHT HERE
return this.emailService.checkEmailExists(control.value).pipe(
map(res => {
//Do what with response
console.log(res);
if (res) {
return of(null);
}
return { taken: true };
})
);
})
);
}
}
}
Here's a Working Code Example for your ref.