0

I'm trying to make a custom asynchronous validator which checks if the email provided already exists on DB or not. When there's error it works fine, but when the error is solved(valid data is entered) it shows Cannot read property 'emailIsTaken' of null

I'm using Template Driven method. Here's how I use.

<input type="email" name="email" [(ngModel)]='email' #mail='ngModel' required [pattern]='emailPattern' validateEmail>

Using error code

<div *ngIf='mail.errors["emailIsTaken"]'>Email already Registered!</div>

Here's my validator file

import { Validator, AbstractControl, NG_ASYNC_VALIDATORS } from '@angular/forms';
import { Directive, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
@Directive({
    selector: '[validateEmail]',
    providers: [{
        provide: NG_ASYNC_VALIDATORS,
        useExisting: EmailValidator,
        multi: true
    }]
})

@Injectable()
export class EmailValidator implements Validator {
    constructor(private http: HttpClient){}
    validate(control: AbstractControl): Promise<any> | Observable<any> {
        return new Promise(resolve => {
            this.http.get('http://surjit.com/email.php?q=' + control.value).subscribe((success)=>{
            if(success === true){
                    resolve(null);
                }
                else{
                    resolve({'emailIsTaken': true});
                }
            });
        });
    }
}

The same error also occurs when I use inbuilt email validator

ScreenShot

1
  • You really should not post screenshots of error text, it is easier and better to copy/paste the text into your question. That said show us the code for SignupComponent.html where the error is originating from. Commented Mar 23, 2018 at 11:36

2 Answers 2

1

This is your problem:

if(success === true){
     resolve(null);
}

You return null in case of successful validation instead of an object with the field 'emailIsTaken'.

What about

if(success === true){
    resolve({'emailIsTaken': false});
}

if this fits to your code?

Sign up to request clarification or add additional context in comments.

4 Comments

I believe this the syntax, we should return null in case of successful test
@user9416413 I think you're not right. You want to validate if the e-mail is free, the good practice is to return the same type of data. You should return emailIsTake in both situations, one with false and the other with true, based on if it's taken or not. Exactly how @DiabolicWords suggested. This way you won't encounter the error you wrote about.
I tried that according to your suggestion, but this doesn't solve my problem. It's still printing the same error
stackoverflow.com/questions/35521583/… Here he used null for successful test
0

If you want tto execute this async then you need to implement the AsyncValidator.

Also you need to return a result from the observable and not subscribe to it. The easiest thing to do here is to use Observable instead of promise but you could chain .toPromise() after .map() as well. You do not want to subscribe here you want to return the observable itself (or the promise) but you do want to have the promise return the expected result which is why you should use map.

On a side note I recommend you switch to using the pipable operators if you have not already done so. See also In Angular rxjs when should I use pipe vs map.

import { AsyncValidator } from '@angular/forms';
import { map } from 'rxjs/operators/map';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class EmailValidator implements AsyncValidator {
    constructor(private http: HttpClient){}

    validate(control: AbstractControl): Promise<any> | Observable<any> {
        return this.http.get('http://surjit.com/email.php?q=' + control.value)
                .pipe(map((success)=> success ? null : {'emailIsTaken': true}));
        }
}

The above is just the changed EmailValidator class.


See the StackBlitz I created based on the above.


Edit

Based on your error screenshot the most likely cause is that you have checks in your HTML on which error should be shown based on the resulting validation and this is not taking into account the fact that the validation result is null if there are no errors. The easiest fix is to use the safe navigation operator ( ?. ) and null property paths ?. Example:

<element *ngIf="errResult?.emailIsTaken">Email is in use</element>

7 Comments

@user9416413 - you need to implement AsyncValidator, and not Validator. That along with what I previously stated like using map.
@user9416413 - My solution above works. If you are having an error it is in code you have not shown. See this stackblitz
@user9416413 - you are making us guess because you did not post the HTML but the most likely cause is trying to access the error result but not taking into account it is null. See my latest edit above.
@user9416413 - if this solves your issue please consider marking an answer using the checkmark on the left side of the answer.
sorry but still my problem is not solved. I'm using error code like <div *ngIf='mail.errors["emailIsTaken"]'>Email already Registered!</div>
|

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.