angular2 异步表单验证 [英] angular2 async form validation

查看:38
本文介绍了angular2 异步表单验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Angular2 完成表单验证.

我试图通过异步调用找出用户名是否已被占用并在我的数据库中使用.

这是我目前的代码:

表单组件:

import {Component, OnInit} from 'angular2/core';从'angular2/common'导入{FORM_PROVIDERS、Control、ControlGroup、FormBuilder、Validators};从 'angular2/http' 导入 {Http, Headers, RequestOptions};从 'angular2/router' 导入 {ROUTER_DIRECTIVES, Router, RouteParams};从'./control.messages'导入{ControlMessages};从'./validation.service'导入{ValidationService};@成分({选择器:'帐户形式',templateUrl: './app/account/account.form.component.html',提供者:[ROUTER_DIRECTICIVES,CaseDataService],指令:[控制消息]})accountForm:控制组;构造函数(私有_accountService:AccountDataService,私有_formBuilder:FormBuilder,私有_router:路由器,私有_params?:RouteParams){this.model = this._accountService.getUser();this.accountForm = this._formBuilder.group({'firstName': ['', Validators.required],'lastName': ['', Validators.required],'userName': ['', Validators.compose([ValidationService.userNameValidator, ValidationService.userNameIsTaken])],....}

验证服务:

导出类 ValidationService {静态 getValidatorErrorMessage(代码:字符串){让配置 = {'必需': '必需','invalidEmailAddress': '无效的电子邮件地址','invalidPassword': '无效密码.密码长度必须至少为 6 个字符,并包含一个数字.','mismatchedPasswords': '密码不匹配.','startsWithNumber': '用户名不能以数字开头.'};返回配置[代码];}静态用户名验证器(控制,服务,标题){//用户名不能以数字开头if (!control.value.match(/^(?:[0-9])/)) {返回空;} 别的 {返回 { 'startsWithNumber': true };}}//需要对数据库进行异步调用以检查用户名是否存在.//可以将 userNameIsTaken 与 userNameValidator 结合使用吗?静态用户名IsTaken(控制:控制){返回新的承诺(解决 => {让标题=新标题();headers.append('Content-Type', 'application/json')//需要调用 api 路由 - _http 将是我的数据服务.如何包含它?this._http.get('ROUTE GOES HERE', { headers: headers }).map(res => res.json()).订阅(数据=> {控制台日志(数据);if (data.userName == true) {解决({采取:真实})}else { 解决({ 采取:假});}})});}}

新代码(更新 x2).ControlGroup 返回 undefined.

 this.form = this.accountForm;this.accountForm = this._formBuilder.group({'firstName': ['', Validators.required],'lastName': ['', Validators.required],'userName': ['', Validators.compose([Validators.required, this.accountValidationService.userNameValidator]), this.userNameIsTaken(this.form, 'userName')],'email': ['', Validators.compose([Validators.required, this.accountValidationService.emailValidator])],'密码': ['', Validators.compose([Validators.required, this.accountValidationService.passwordValidator])],'确认':['',Validators.required]});};用户名IsTaken(组:任何,用户名:字符串){返回新的承诺(解决 => {this._accountService.read('/username/' + group.controls[userName].value).订阅(数据=> {数据 = 数据如果(数据){解决({采取:真实})} 别的 {解决(空);}});})};

HTML:

<span class="input-group-label">用户名</span><input class="input-group-field" type="text" required [(ngModel)]="model.userName" ngControl="userName" #userName="ngForm"><control-messages control="userName"></control-messages><div *ngIf="taken">用户名已被使用.</div>

解决方案

你应该这样定义你的异步验证器:

'userName': ['', ValidationService.userNameValidator,ValidationService.userNameIsTaken],

而不是使用 Validators.compose 方法.事实上,这里是参数对应的:

'': [ '', syncValidators, asyncValidators ]

此外,当不使用用户名而不是 `{taken: false}

时,您应该使用 null 进行解析

if (data.userName == true) {解决({采取:真实})} 别的 {解决(空);}

有关更多详细信息,请参阅此文章(字段的异步验证"部分):

编辑

也许我的回答不够清楚.您仍然需要使用 Validators.compose 但前提是您有多个同步验证器:

this.accountForm = this._formBuilder.group({'firstName': ['', Validators.required],'lastName': ['', Validators.required],'用户名': ['', Validators.compose([Validators.required,this.accountValidationService.userNameValidator], this.userNameIsTaken],'email': ['', Validators.compose([Validators.required,this.accountValidationService.emailValidator]],'密码': ['', Validators.compose([Validators.required,this.accountValidationService.passwordValidator]],'确认':['',Validators.required]});};

编辑 1

您需要利用 ngFormControl 而不是 ngControl ,因为您使用 FormBuilder 类定义控件.

<span class="input-group-label">用户名</span><input class="input-group-field" type="text" required [(ngModel)]="model.userName" [ngControl]="accountForm.controls.userName" ><control-messages [control]="accountForm.controls.userName"></control-messages><div *ngIf="accountForm.controls.userName.errors && accountForm.controls.userName.errors.taken">用户名已被使用.</div>

查看这篇文章了解更多详情:

I am trying to accomplish a piece of a form validation with Angular2.

I am trying to find out, via an asynchronous call, if a username has already been taken and used in my database.

Here is my code so far:

FORM COMPONENT:

import {Component, OnInit} from 'angular2/core';
import {FORM_PROVIDERS, Control, ControlGroup, FormBuilder, Validators} from 'angular2/common';
import {Http, Headers, RequestOptions} from 'angular2/http';
import {ROUTER_DIRECTIVES, Router, RouteParams} from 'angular2/router';
import {ControlMessages} from './control.messages';
import {ValidationService} from './validation.service';

@Component({
    selector: 'account-form',
    templateUrl: './app/account/account.form.component.html',
    providers: [ROUTER_DIRECTIVES, CaseDataService],
    directives: [ControlMessages]
})

accountForm: ControlGroup;

constructor(private _accountService: AccountDataService,
    private _formBuilder: FormBuilder, private _router: Router, private _params?: RouteParams) {
    this.model = this._accountService.getUser();

    this.accountForm = this._formBuilder.group({
        'firstName': ['', Validators.required],
        'lastName': ['', Validators.required],
        'userName': ['', Validators.compose([ValidationService.userNameValidator, ValidationService.userNameIsTaken])],

....
}

VALIDATION SERVICE:

export class ValidationService {


static getValidatorErrorMessage(code: string) {
    let config = {
        'required': 'Required',
        'invalidEmailAddress': 'Invalid email address',
        'invalidPassword': 'Invalid password. Password must be at least 6 characters long, and contain a number.',
        'mismatchedPasswords': 'Passwords do not match.',
        'startsWithNumber': 'Username cannot start with a number.'
    };
    return config[code];
}

static userNameValidator(control, service, Headers) {
    // Username cannot start with a number
    if (!control.value.match(/^(?:[0-9])/)) {
        return null;
    } else {
        return { 'startsWithNumber': true };
    }
}
  // NEEDS TO BE AN ASYNC CALL TO DATABASE to check if userName exists. 
// COULD userNameIsTaken be combined with userNameValidator??

static userNameIsTaken(control: Control) {
    return new Promise(resolve => {
        let headers = new Headers();
        headers.append('Content-Type', 'application/json')

        // needs to call api route - _http will be my data service. How to include that?

        this._http.get('ROUTE GOES HERE', { headers: headers })
            .map(res => res.json())
            .subscribe(data => {
                console.log(data);
                if (data.userName == true) {
                    resolve({ taken: true })
                }
                else { resolve({ taken: false }); }
            })
    });
}
}

NEW CODE (UPDATED x2). ControlGroup is returning undefined.

    this.form = this.accountForm;
    this.accountForm = this._formBuilder.group({
        'firstName': ['', Validators.required],
        'lastName': ['', Validators.required],
        'userName': ['', Validators.compose([Validators.required, this.accountValidationService.userNameValidator]), this.userNameIsTaken(this.form, 'userName')],
        'email': ['', Validators.compose([Validators.required, this.accountValidationService.emailValidator])],
        'password': ['', Validators.compose([Validators.required, this.accountValidationService.passwordValidator])],
        'confirm': ['', Validators.required]
    });         
};

userNameIsTaken(group: any, userName: string) {
    return new Promise(resolve => {

        this._accountService.read('/username/' + group.controls[userName].value)
            .subscribe(data => {
                data = data
                if (data) {
                    resolve({ taken: true })
                } else {
                    resolve(null);
                }
            });
    })
};

HTML:

<div class="input-group">
    <span class="input-group-label">Username</span>
    <input class="input-group-field" type="text" required [(ngModel)]="model.userName" ngControl="userName" #userName="ngForm">
    <control-messages control="userName"></control-messages>
    <div *ngIf="taken">Username is already in use.</div>
</div>

解决方案

You should define your async validator this way:

'userName': ['', ValidationService.userNameValidator, 
       ValidationService.userNameIsTaken],

And not with the Validators.compose method. As a matter of fact, here is what parameters correspond to:

'<field-name>': [ '', syncValidators, asyncValidators ]

Moreover you should resolve with null when the user name isn't taken instead of `{taken: false}

if (data.userName == true) {
  resolve({ taken: true })
} else {
  resolve(null);
}

See this article for more details (section "Asynchronous validation for fields"):

Edit

Perhaps my answer isn't clear enough. You still need to use Validators.compose but only when you have several synchronous validators:

this.accountForm = this._formBuilder.group({
    'firstName': ['', Validators.required],
    'lastName': ['', Validators.required],
    'userName': ['', Validators.compose([
             Validators.required,
             this.accountValidationService.userNameValidator
          ], this.userNameIsTaken],
    'email': ['', Validators.compose([
             Validators.required,
             this.accountValidationService.emailValidator
          ]],
    'password': ['', Validators.compose([
             Validators.required,
             this.accountValidationService.passwordValidator
          ]],
    'confirm': ['', Validators.required]
  });         
};

Edit1

You need to leverage the ngFormControl instead of the ngControl one because you define your controls using the FormBuilder class.

<div class="input-group">
  <span class="input-group-label">Username</span>
  <input class="input-group-field" type="text" required [(ngModel)]="model.userName" [ngControl]="accountForm.controls.userName" >
  <control-messages [control]="accountForm.controls.userName"></control-messages>
  <div *ngIf="accountForm.controls.userName.errors && accountForm.controls.userName.errors.taken">Username is already in use.</div>
</div>

See this article for more details:

这篇关于angular2 异步表单验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆