简体   繁体   中英

Async Custom Validation at Ionic3

I want to check availability of email or the registered email cannot be submitted any more. The scenario: user types email in form then system checks if in database the email was already saved then system triggers error. I tried to display the result that if "count > 0" then the output is true so that return object "{is_notavail: true}". However, in template "is_notavail" always return "false". Strangely, form color is red neither I submit new nor saved email. These are my codes.

email.ts (validator)

import { FormControl } from '@angular/forms';
import { UserServiceProvider } from '../../providers/user-service/user-service';
import 'rxjs/add/operator/toPromise';


export class EmailValidator{
    static userService: UserServiceProvider;
    constructor(userService: UserServiceProvider){
        EmailValidator.userService = userService;
    }
    checkEmailAvail(control: FormControl){
    return EmailValidator.userService.isExist(control.value).toPromise().then(count => {
        if(count>0){
            return {is_notavail: true};
        }else return null;
    });

    }

}

user-service.ts (service)

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Observable } from "rxjs/Observable";
import { User } from "../../models/user.model";
import { BehaviorSubject } from "rxjs/BehaviorSubject";


@Injectable()
export class UserServiceProvider {
  users: Observable<User[]>;
  private _users: BehaviorSubject<User[]>;
  private baseUrl: string;
  private dataStore: {
    users: User[]
  };
  constructor(public http: Http) {
    this.baseUrl = 'api/v1/user';
    this.dataStore = {users: []};
    this._users = <BehaviorSubject<User[]>> new BehaviorSubject([]);
    this.users = this._users.asObservable();
  }

  isExist(email: string){  
      return this.http.post(this.baseUrl + '/isexist', {'email': email}).map(data => data.json().data);
  }
}

register.ts (pages)

import { Component } from '@angular/core';
import { NavController, IonicPage, Loading, AlertController, LoadingController } from 'ionic-angular';
import { FormBuilder, FormGroup, Validators, FormControl } from "@angular/forms";
import { UserServiceProvider } from '../../providers/user-service/user-service';
import { User } from "../../models/user.model";
import { PasswordValidator } from '../../validators/password/password';
import { EmailValidator } from "../../validators/email/email";

@IonicPage()
@Component({
  selector: 'page-register',
  templateUrl: 'register.html',
})

export class RegisterPage {
  submitAttempt: boolean = false;  
  registerForm: FormGroup;
  control: FormControl;
  _isNotAvail: boolean = false;
  loading: Loading;
  user: User = {name: '', email: '', password: ''};
  constructor(
    public navCtrl: NavController, 
    private formBuilder: FormBuilder, 
    private userServiceProvider: UserServiceProvider,
    private alertCtrl: AlertController,
    private loadingCtrl: LoadingController) {

    this.registerForm = this.formBuilder.group({
      name: ['',  Validators.compose([Validators.required])],
      email: ['', Validators.compose([Validators.required, Validators.email, (new EmailValidator(this.userServiceProvider)).checkEmailAvail])],
      password: ['', Validators.compose([Validators.required, Validators.minLength(8)])],
      confPassword: ['', Validators.compose([Validators.required])]
    }, {
      validator: PasswordValidator.confPassword('password', 'confPassword')
    });

  }
}

register.html

     <ion-item *ngIf="registerForm.get('email').errors && registerForm.get('email').dirty">
        <p *ngIf="registerForm.get('email').hasError('required')">Email harus diisi.</p>
        <p *ngIf="registerForm.get('email').hasError('email')">Email tidak sesuai format.</p>
        <p *ngIf="registerForm.get('email').hasError('is_notavail')">Email sudah terdaftar.</p>
    </ion-item>

There are Validators and AsyncValidators. If you are making a request to the server you should make this an AsyncValidator. To do that, provider the validator in an array in the 3rd parameter.

email: ['', [Validators.required, Validators.email], [new EmailValidator(this.userServiceProvider).checkEmailAvail]],

Also I noticed in the EmailValidator constructor you set the userServiceProvider as a static property on EmailValidator. I assume you are doing this because userServiceProvider is undefined when the checkEmailAvail validator function runs. This is because it's running with the scope of the caller. Make the userServiceProvider an instance property (instead of a static property) and pass the function like this-

var emailValidator = new EmailValidator(this.userServiceProvider);

.

email: ['', [Validators.required, Validators.email], [emailValidator.checkEmailAvail.bind(emailValidator)]],

Thank you Micah. I explain my problem in deep. Actually, there are two mistakes.

The first I was wrong put AsyncValidation in second param instead of third param, you fix my code, this is the right one:

let emailValidator = new EmailValidator(this.userService);
this.registerForm = this.formBuilder.group({
  name: ['',  Validators.compose([Validators.required])],
  email: ['', Validators.compose([Validators.required, Validators.email]), emailValidator.checkEmailAvail.bind(emailValidator)],
  password: ['', Validators.compose([Validators.required, Validators.minLength(8)])],
  confPassword: ['', Validators.compose([Validators.required])]
}, {
  validator: PasswordValidator.confPassword('password', 'confPassword')
});

The second my validator should be promise and uses resolve

import { FormControl } from '@angular/forms';
import { UserServiceProvider } from '../../providers/user-service/user-service';

export class EmailValidator{
    static userService: UserServiceProvider;
    constructor(userService: UserServiceProvider){
        EmailValidator.userService = userService;
    }
    checkEmailAvail(control: FormControl){
    return new Promise ( resolve => {
            EmailValidator.userService.isExist(control.value).subscribe(count => {
                if(count>0){                  
                    return resolve({is_notavail: true});
                }else {
                return resolve(null);
                }

    })
    })
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM