Angular 11异步验证器触发真实响应的无限循环请求

Posted

技术标签:

【中文标题】Angular 11异步验证器触发真实响应的无限循环请求【英文标题】:Angular 11 async validator triggering endless loop of requests on true response 【发布时间】:2021-03-01 06:43:34 【问题描述】:

因此,我正在创建一个带有异步现有用户验证的简单注册表单,它执行对我的 API 的 http 请求,该请求为现有用户返回一个布尔值。

组件

import  Component, OnInit  from '@angular/core';
import  FormBuilder, FormGroup, Validators  from '@angular/forms';
import  UserTakenValidatorService  from '../../services/user-taken.validator.service';

@Component(
  selector: 'app-signup',
  templateUrl: './signup.component.html',
  styleUrls: ['./signup.component.less'],
)
export class SignupComponent implements OnInit 
  public signupForm: FormGroup;
  public hide = true;

  constructor(
    private formBuilder: FormBuilder,
    private checkUserTaken: UserTakenValidatorService,
  ) 

  ngOnInit(): void 
    this.signupForm = this.formBuilder.group(
      email: ['', [Validators.required, Validators.email]],
      fullName: ['', [Validators.required, Validators.maxLength(40)]],
      userName: [
        '',
        [Validators.required, Validators.maxLength(20)],
        this.checkUserTaken.checkUserNameTaken(),
      ],
      password: ['', [Validators.required, Validators.minLength(8), Validators.maxLength(20)]],
    );
  

  signup() 
    console.log(this.signupForm.controls.userName.errors);
  

这是验证器

import  HttpClient  from '@angular/common/http';
import  Injectable  from '@angular/core';
import  AbstractControl  from '@angular/forms';
import   map  from 'rxjs/operators';

const API_URL = 'http://localhost:3000';

@Injectable( providedIn: 'root' )
export class UserTakenValidatorService 
  constructor(private http: HttpClient) 

  checkUserNameTaken() 
    return (control: AbstractControl) =>              
      return this.verifyUsername(control.value)
        .pipe(map((isTaken) => (isTaken ?  userNameTaken: true  : null)))
    ;
  

  private verifyUsername(userName: string) 
    return this.http.get<boolean>(`$API_URL/user/exists/$userName`);
  

当输入现有用户(即来自 API 的 true 响应)时,这会触发无限循环的请求,这些用户也不会向 signupForm.controls.userName.errors 添加错误,并且会在第一个错误时停止回应。

P.S.:依赖是 @angular/core/forms/common 11.0.0rxjs 6.6.0

【问题讨论】:

【参考方案1】:

Angular HttpClient 默认需要一个 JSON。您的回复似乎只包含一个字符串,它代表一个布尔值。

请尝试以下方法

private verifyUsername(userName: string) 
    return this.http.get<string>(`$API_URL/user/exists/$userName`,  responseType: 'text' ).pipe(
      map(stringBoolean => stringBoolean === 'true'),
    );
  

【讨论】:

我在更彻底的分析中删除了我之前的评论原因,即使它抛出了一个奇怪的“没有重载匹配这个调用”(在 Angular 文档中作为 Overload #3),它确实编译返回一个string 不断触发循环。更改为 responseType: 'json' (重载#15)似乎有效,但响应类型为boolean,因此在地图条件下始终返回false;试图删除它,带回循环。

以上是关于Angular 11异步验证器触发真实响应的无限循环请求的主要内容,如果未能解决你的问题,请参考以下文章

Angular为唯一的用户名创建异步验证器

Angular 反应式表单自定义控件异步验证

Angular 2 - 异步管道中的无限循环

Angular 2 提交时触发表单验证

如何在 Angular2 中触发表单验证器

触发 Angular 表单提交中所有字段的验证