调用异步验证器时,Angular 服务始终未定义

Con*_*eer 0 typescript angular angular-reactive-forms

我已经查了很多其他问题,但没有一个有效。

我正在尝试创建一个异步验证器来检查输入的用户名是否已经存在。但是每当我在输入字段中输入字母时,我都会收到一条错误消息,指出我的userService实例是undefined.

以下是我的UserService

export interface UsernameCheck {
  info: string,
  usernameAvailable: boolean;
}

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private apiUrl = 'http://localhost:5001/project-f-angular/us-central1';

  constructor(
    private http: HttpClient
  ) { }

  checkUsername(username: string) {
    const params = new HttpParams().set('username', username);

    return this.http.get<UsernameCheck>(`${this.apiUrl}/checkUsername`, {params});
  }
}
Run Code Online (Sandbox Code Playgroud)

http 请求指向本地运行的 Firebase Cloud Functions 模拟器。

这是我正在使用它的组件:

export class SignUpComponent implements OnInit {
  signUpForm: FormGroup;

  constructor(
    private userService: UserService,
    private formBuilder: FormBuilder) {
  }

  ngOnInit() {
    this.signUpForm = this.formBuilder.group({
      username: [null, Validators.required, this.existingUsername],
      email: [null, [Validators.required, Validators.email]],
      password: [null, Validators.required],
      confirmPassword: [null, Validators.required]
    });
  }

  existingUsername(control: FormControl): Promise<any> | Observable<any> {
    console.log(control.value);
    return this.userService.checkUsername(control.value)
      .pipe(
        map(res => {
          return res.usernameAvailable ? null : {existingUsername: true};
        })
      );
  }
}
Run Code Online (Sandbox Code Playgroud)

这是在输入字段中输入第一个字母后出现的错误:

ERROR TypeError: Cannot read property 'userService' of undefined
    at existingUsername (sign-up.component.ts:45)
    at forms.js:1492
    at Array.map (<anonymous>)
    at _executeAsyncValidators (forms.js:1488)
    at FormControl.asyncValidator (forms.js:1446)
    at FormControl._runAsyncValidator (forms.js:4100)
    at FormControl.updateValueAndValidity (forms.js:4053)
    at FormControl.setValue (forms.js:4692)
    at updateControl (forms.js:3299)
    at DefaultValueAccessor.onChange (forms.js:3271)
Run Code Online (Sandbox Code Playgroud)

我还将我的服务添加到了app.module.ts下面providers

如果我订阅我的userService内部ngOnInit,我的方法将按预期工作并返回正确的响应。

我对反应式表单和验证器的东西很陌生。

那么,有人知道我做错了什么吗?

mis*_*ing 6

您需要这样做bind才能this将正确的上下文传递给验证器。

this.signUpForm = this.formBuilder.group({
   username: [null, Validators.required, this.existingUsername.bind(this)],  // <--
   email: [null, [Validators.required, Validators.email]],
   password: [null, Validators.required],
   confirmPassword: [null, Validators.required]
});
Run Code Online (Sandbox Code Playgroud)

这是演示解决方案的stackblitz示例。

希望这可以帮助。