验证用户名存在异步

时间:2018-12-01 14:09:24

标签: angular asynchronous rxjs angular-reactive-forms

我试图通过说一个用户名是否可用异步验证器来验证用户名,我尝试了许多解决方案,但我不知道要完成这项工作,我遇到了这个错误:

Error: Expected validator to return Promise or Observable.

我的方法validateUsername()不完整,如何使它工作?

register.component.ts

this.registerForm = this.fb.group({
            username: ['', [Validators.required], this.validateUsername.bind(this)],
            email: ['', [Validators.required,
                Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$')]],
            password: this.fb.group({
                pwd: ['', [Validators.required, Validators.minLength(1)]], // todo
                confirmpwd: ['', [Validators.required, Validators.minLength(1)]]// todo
            }, {
                validator: this.mustMatch('pwd', 'confirmpwd'),
            }),
            birthday: ['', Validators.required]
        });
    }


validateUsername(control: AbstractControl) {
        this.userservice.checkUserExist(control.value).subscribe(
            res => {
                this.exist = 'username available ';
            },
            error => {
                this.exist = 'username unavailable ';
            }
        );
    }

register.component.html

<div class="form-group">
                <label for="inputName" class="font-weight-bold">Usuario</label>
                <div class="input-group Name">
                    <div class="input-group-prepend">
                        <div class="input-group-text"><i class="fa fa-user" aria-hidden="true"></i>
                        </div>
                    </div>
                    <input type="text" class="form-control"  id="inputName" name="inputName" formControlName="username"
                           placeholder="Identificador de usuario">
                </div>
                <div *ngIf="username.invalid && username.touched" class="col-4 p-0 ml-5 text-danger">
                    <p *ngIf="username.errors?.required">
                        Escoger un nombre de usuario
                    </p>
                    <p *ngIf="username.errors?.usertaken">
                        Este usuario ya existe
                    </p>
                </div>
            </div>

2 个答案:

答案 0 :(得分:2)

这是给你的例子

一个简单的组件初始化我们的反应形式并定义我们的异步验证器:validateEmailNotTaken。请注意,FormBuilder.group声明中的表单控件如何将异步验证器作为第三个参数。在这里,我们仅使用一个异步验证器,但您希望将多个异步验证器包装在一个数组中:

app.component.ts

import { Component, OnInit } from '@angular/core';
import {
  FormBuilder,
  FormGroup,
  Validators,
  AbstractControl
} from '@angular/forms';

import { SignupService } from './signup.service';

@Component({ ... })
export class AppComponent implements OnInit {
  myForm: FormGroup;

  constructor(
    private fb: FormBuilder,
    private signupService: SignupService
  ) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      name: ['', Validators.required],
      email: [
        '',
        [Validators.required, Validators.email],
        this.validateEmailNotTaken.bind(this)
      ]
    });
  }

  validateEmailNotTaken(control: AbstractControl) {
    return this.signupService.checkEmailNotTaken(control.value).map(res => {
      return res ? null : { emailTaken: true };
    });
  }
}

我们的验证器与典型的自定义验证器非常相似。在这里,我们直接在组件类中定义了验证器,而不是单独的文件。这使得访问我们注入的服务实例更加容易。还请注意,我们如何绑定此值以确保它指向组件类。

我们还可以在自己的文件中定义异步验证器,以便更轻松地重用和分离关注点。唯一棘手的部分是找到一种提供我们的服务实例的方法。例如,在这里,我们创建一个类,该类具有一个createValidator静态方法,该方法接受我们的服务实例并返回我们的验证函数:

async-email.validator.ts

import { AbstractControl } from '@angular/forms';
import { SignupService } from '../signup.service';

export class ValidateEmailNotTaken {
  static createValidator(signupService: SignupService) {
    return (control: AbstractControl) => {
      return signupService.checkEmailNotTaken(control.value).map(res => {
        return res ? null : { emailTaken: true };
      });
    };
  }
}

然后,回到我们的组件中,我们导入ValidateEmailNotTaken类,我们可以像这样使用验证器:

ngOnInit() {
  this.myForm = this.fb.group({
    name: ['', Validators.required],
    email: [
      '',
      [Validators.required, Validators.email],
      ValidateEmailNotTaken.createValidator(this.signupService)
    ]
  });
}

HTML文件

<form [formGroup]="myForm">
  <input type="text" formControlName="name">
  <input type="email" formControlName="email">

  <div *ngIf="myForm.get('email').status === 'PENDING'">
    Checking...
  </div>
  <div *ngIf="myForm.get('email').status === 'VALID'">
     Email is available!
  </div>

  <div *ngIf="myForm.get('email').errors && myForm.get('email').errors.emailTaken">
     this email is already taken!
  </div>
</form>

答案 1 :(得分:0)

表格

 public registerForm: FormGroup;
 constructor(private authService:AuthentificationService,
              private formBuilder: FormBuilder,
              ) { }

this.registerForm = this.formBuilder.group({
  firstname: ['', Validators.required],
  lastname: ['', Validators.required],
  username: ['', [Validators.required,this.validateUsername()]],
  email: ['', [Validators.required, Validators.email]],
  password: ['', [Validators.required, Validators.minLength(6)]],
  confirmPassword: ['', Validators.required]
  }, {
  validator: MustMatch('password', 'confirmPassword')
  }); 

  get f() { return this.registerForm.controls; } // convenience getter for easy access to form fields

验证器

 private validateUsername(): ValidatorFn {
    return (control: AbstractControl) => {
      if (control.value.length != 0) {
        this.authService.checkUsername(control.value).subscribe( data => { 
          if(data) control.setErrors({'alreadyExist': true}) ;
          else return null;
        })
      }else return null;
    }
  }

HTML

  <mat-form-field>
          <input matInput placeholder="User Name" required autocomplete="off"  formControlName="username">
          <mat-icon matSuffix>perm_identity</mat-icon>
          <mat-error *ngIf= "f.username.errors?.required">
            Username is required
          </mat-error>
          <mat-error  *ngIf= " f.username.errors?.alreadyExist">
             this username already exists in our database
          </mat-error>
    </mat-form-field>