Angular 2多个验证器

Seb*_*sen 42 typescript angular

是否可以在表单字段上有多个验证器?我尝试了这个,但它导致了一些奇怪的错误(字段永远无效,即使满足要求)

this.username = new Control('', Validators.minLength(5), Validators.required);
Run Code Online (Sandbox Code Playgroud)

我如何使用多个验证器?

Gün*_*uer 63

您可以使用组合验证器 Validators.compose()

this.username = new Control('', 
    Validators.compose(
        [Validators.minLength(5), Validators.required]));
Run Code Online (Sandbox Code Playgroud)

用于异步验证器使用

this.username = new Control('', null,
    Validators.composeAsync(
        [someAsyncValidator, otherAsyncValidator]));
Run Code Online (Sandbox Code Playgroud)

异步验证器存在未解决的问题,尤其是与异步验证器结合使用的同步验证器不起作用

要使同步验证器与异步验证器一起工作,请将同步验证器包装在promises中,并将它们组合为async valdiators,如

this.username = new Control('', null,
    Validators.composeAsync([
        (control:Control) => Promise.resolve(Validators.minLength(5)(control)), 
        (control:Control) => Promise.resolve(Validators.required(control)),
        someAsyncValidator, otherAsyncValidator
    ]));
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供这么好的解决方案!一个问题:Validators.compose([ // myValidators ]) 和仅将验证器作为数组作为第三个参数传递而不使用 Validators.compose() 有什么区别? (3认同)
  • 真的没有什么区别。据我所知,当我发布此答案时,尚不支持仅通过它们(至少不适用于异步验证器)。 (3认同)
  • 有关同步和异步验证器组合的问题似乎已经解决! (2认同)

Ank*_*nka 38

这个问题已得到解决

你可以制作一系列验证器

this.username = new FormControl('', [ Validators.minLength(5), Validators.required ]); 
Run Code Online (Sandbox Code Playgroud)

  • 与使用“compose”有什么区别? (9认同)
  • 这个解决方案的问题是什么? (2认同)

Tim*_*rez 8

我建议使用Validators.compose()方法组合所有非异步验证器,并为任何异步调用分别传入Validators.composeAsync().

基本上FormControl的构造函数args如下:

  1. formState(或简称初始起始值)
  2. 验证器(我建议在这里使用Validators.compose([...]))
  3. asyncValidators(我建议在这里使用Validators.composeAsync([...]))

使用FormBuilder的示例(随意使用直接控件):

this.acctForm = this.fb.group({
            'name': [
                '',
                Validators.compose([
                    Validators.required, Validators.minLength(2), Validators.maxLength(20), Validators.pattern('[a-zA-Z]')
                ])
            ],
            'cellNumber': [
                '',
                Validators.compose([
                    Validators.required, Validators.pattern('[0-9]{10}')
                ]),
                Validators.composeAsync([
                    this.checkPhoneValid.bind(this)
                ])
            ]
        });
Run Code Online (Sandbox Code Playgroud)

这有助于避免异步验证,直到非异步验证器有效(不包括初始检查,可以轻松处理,详见下文).

所有组合示例(验证器,asyncValidators和debouncing):

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


@Component({
    selector: 'app-sandbox',
    templateUrl: './sandbox.component.html',
    providers: []
})
export class FormControlsDemoComponent implements OnInit {
    private debouncedTimeout;
    public acctForm: FormGroup;

    constructor(private http: Http, private fb: FormBuilder) {
        // @note Http should never be directly injected into a component, for simplified demo sake...
    }

    ngOnInit() {
        this.acctForm = this.fb.group({
            // Simple Example with Multiple Validators (non-async)
            'name': [
                '',
                Validators.compose([
                    Validators.required, Validators.minLength(2), Validators.maxLength(20), Validators.pattern('[a-zA-Z]')
                ])
            ],
            // Example which utilizes both Standard Validators with an Async Validator
            'cellNumber': [
                '',
                Validators.compose([
                    Validators.required, Validators.minLength(4), Validators.maxLength(15), Validators.pattern('[0-9]{10}')
                ]),
                Validators.composeAsync([
                    this.checkPhoneValid.bind(this) // Important to bind 'this' (otherwise local member context is lost)
                    /*
                        @note if using a service method, it would look something like this...
                        @example:
                            this.myValidatorService.phoneUniq.bind(this.myValidatorService)
                    */
                ])
            ],
            // Example with both, but Async is implicitly Debounced
            'userName': [
                '',
                Validators.compose([
                    Validators.required, Validators.minLength(4), Validators.maxLength(15), Validators.pattern('[a-zA-Z0-9_-]')
                ]),
                Validators.composeAsync([
                    this.checkUserUniq.bind(this) // @see above async validator notes regarding use of bind
                ])
            ]
        });

    }

    /**
     * Demo AsyncValidator Method
     * @note - This should be in a service
     */
    private checkPhoneValid(control: AbstractControl): Promise<any> {
        // Avoids initial check against an empty string
        if (!control.value.length) {
            Promise.resolve(null);
        }

        const q = new Promise((resolve, reject) => {
            // determine result from an http response or something...
            let result = true;

            if (result) {
                resolve(null);
            } else {
                resolve({'phoneValidCheck': false});
            }
        });
        return q;
    }

    /**
     * Demo AsyncValidator Method (Debounced)
     * @note - This should be in a service
     */
    private checkUserUniq(control: AbstractControl): Promise<any> {
        // Avoids initial check against an empty string
        if (!control.value.length) {
            Promise.resolve(null);
        }

        clearTimeout(this.debouncedTimeout);

        const q = new Promise((resolve, reject) => {

            this.debouncedTimeout = setTimeout(() => {

                const req = this.http
                    .post('/some/endpoint', { check: control.value })
                    .map(res => {
                        // some handler logic...
                        return res;
                    });

                req.subscribe(isUniq => {
                    if (isUniq) {
                        resolve(null);
                    } else {
                        resolve({'usernameUnique': false });
                    }
                });

            }, 300);
        });
        return q;
    }

}
Run Code Online (Sandbox Code Playgroud)

有些人喜欢通过绑定到控件的Observable valueChanges来破坏去抖动的异步验证器,如下所示:

this.someControl.debounceTime(300).subscribe(val => {
      // async call...
});
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,我个人不建议这样做,因为它增加了不必要的复杂性.

注意:自从撰写本文以来,最新版本的Angular(2和4)应该可以使用.