Can someone help me with creating an asynchronous validator for a reactive form control that checks if a username already exists? Below is the code for the async validator:
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'; // not the actual URL
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);
}
}
);
}
}
Trying to use this validator results in the error: "core.js:4197 ERROR TypeError: Cannot read property 'http' of undefined"
I suspect the issue has to do with the usage of 'this', but I'm unsure why it's not working... To troubleshoot, I inserted a
console.log(this.apiUrl)
within the function, outside the promise block, just to test, and encountered the same error: "core.js:4197 ERROR TypeError: Cannot read property 'apiUrl' of undefined"...
If anyone can shed light on what I might be doing incorrectly and how to resolve it, I would greatly appreciate it.
EDIT:
In my reactive form ts file, I call my service as shown below:
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({
// ... many controls before ...
'username': new FormControl(username, [
Validators.required,
Validators.minLength(3),
Validators.maxLength(30),
Validators.pattern(/^[a-zA-ZÀ-ÿ\u00f1\u00d1]+(\s*[a-zA-ZÀ-ÿ\u00f1\u00d1]*)*[a-zA-ZÀ-ÿ\u00f1\u00d1]+$/)
], this.userdataService.checkUsername), // <-- async validator here
// ... form continues...
}
loadProvinces() {
this.provincesLoading = true;
this.locationService.getProvinces().subscribe(response => {
this.provinces = response;
this.provincesLoading = false;
});
}