1

So, I'm creating a simple registration form with an async existing user validation, which executes a http request to my API that returns a boolean for existing user.

The component:

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);
  }
}

And this is the validator:

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}`);
  }
}

This has been triggering an endless loop of requests when inputting an existing user (i.e. on true responses from API) that also don't add errors to signupForm.controls.userName.errors and that stops on the first false response.

P.S.: Dependencies are @angular/core/forms/common 11.0.0 and rxjs 6.6.0

1 Answer 1

1

The Angular HttpClient expects a JSON per default. It seems your response contains a string only, which represents a boolean.

Please try the following

private verifyUsername(userName: string) {
    return this.http.get<string>(`${API_URL}/user/exists/${userName}`, { responseType: 'text' }).pipe(
      map(stringBoolean => stringBoolean === 'true'),
    );
  }
Sign up to request clarification or add additional context in comments.

1 Comment

I deleted my previous comment cause on a more thorough analysis, even though it throws an weird "No overload matches this call" (which is in Angular documentation as Overload #3), it does compile returning a string that keeps triggering the loop. Changing to { responseType: 'json' } (Overload #15) appeared to work, but type of response came as boolean, thus always returning false on the map condition; trying to remove it, brought back the loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.