0

I have a custom validator who verify that a serial number exist in my database. I would like to display an specific error message in the field of the form when the serial is not found but I can't do it. I tried different methods but the result is not good. When I try to insert this code in my template

<div *ngIf="deviceInfos.controls.serial.errors && serial != null">
              Error
            </div>

The error message is displayed even before the user enter in the field. I'm new in Angular and I'm actually lost in that problem.

This is my custom validator

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { AbstractControl, AsyncValidator, FormControl } from '@angular/forms';
import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';


@Injectable({
  providedIn: 'root',
})
export class HttpRequestValidation implements AsyncValidator {
  
  constructor(private http: HttpClient) {}

  validate = (control: AbstractControl) => {

    const { value } = control;
    console.log(value);
    
    return this.http.get<any>(`http://127.0.0.1/backend/api-vitoapp/verify-serial.php?serial=${value}`)
      .pipe(

        map(() => {
            
          return null;
        }),
        catchError((err) => {
 
          console.log(err);
          return of (err);
        })
      );
  };
}

And this is the part of my component

 deviceSelected : any;
  serial = new FormControl('');
  
  constructor(private fb: FormBuilder,
              private hardwareCheckService: HardwareCheckService) {
  }

  ngOnInit() {
    
    this.deviceInfos = this.fb.group({
      serial: [null, [Validators.required, this.httpRequestValidation.validate]],
      deviceType: [this. deviceTypeOptions[0]],
    });
  }

Can someone help me? Many thanks in advance.

3 Answers 3

1

Have a look at this. This will help.

import { FormControl } from '@angular/forms';

export function validateJson(input: FormControl): object | null {
    try {
        if (input.value) {
            JSON.parse(input.value);
        }

        return null;
    } catch (error) {
        return { invalidFormat: {message: "your message here"} };
    }
}

In HTML if an error exists display a message as follows

<div *ngIf="formControl.errors.invalidFormat && formControl.dirty">
        {{ formControl.errors.invalidFormat.message}}
</div>
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your response and your help. I tried to insert your code in my validato like this ` return null; }), catchError((err) => { console.log(err); return of ({ invalidFormat: {message: 'your message here'} }); }) );` and insert in my template the ngIf for the error message like this <div *ngIf="serial.errors.invalidFormat && serial.dirty"> {{ serial.errors.invalidFormat.message}} </div> but in my console I get the error Cannot read property invalidFormat of null.
change your code to: <div *ngIf="serial.errors.invalidFormat && serial.dirty">{{ serial?.errors?.invalidFormat.message}} </div> This way it would check the null object and you won't see that error in the console while there is no validation error.
0

Finally I modified my validator like this

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { AbstractControl, AsyncValidator, FormControl } from '@angular/forms';
import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';


@Injectable({
  providedIn: 'root',
})
export class HttpRequestValidation implements AsyncValidator {
  
  constructor(private http: HttpClient) {}

  validate = (control: AbstractControl) => {

    const { value } = control;
    console.log(value);
    
    return this.http.get<any>(`http://127.0.0.1/backend/api-vitoapp/verify-serial.php?serial=${value}`)
      .pipe(

        map(() => {
            
          return null;
        }),
        catchError((err) => {
 
          console.log(err);
          return of ({ invalidFormat: {message: 'Device not found in database'} });
        })
      );
  };


}

and modified my template like this

<div *ngIf="deviceInfos.controls.serial.hasError('invalidFormat')">
       <span class="alert">{{ deviceInfos.get('serial').errors.invalidFormat.message}}</span> 
</div>

I don't know if it's the best way to do that but now it's work

Comments

0

Since I cannot comment: You're solution works, but it's bad practice to use function calls in the html due to performance issues because the function keeps getting called with every detection cycle.

Therefore I'd propose this, based on your template code:

<div *ngIf="deviceInfos.controls.serial.errors?['invalidFormat']">
       <span class="alert">{{ deviceInfos.controls.serial.errors?['invalidFormat']}} <span>
</div>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.