2016-05-11 6 views
6

Возможно ли иметь несколько валидаторов в поле формы? Я попробовал это, но это привело к некоторым странным ошибкам (поле никогда не было действительным, даже если требования были удовлетворены)Угловой 2 Несколько валидаторов

this.username = new Control('', Validators.minLength(5), Validators.required); 

Как я могу использовать несколько валидаторов?

ответ

17

Вы можете комбинировать валидаторы с помощью Validators.compose()

this.username = new Control('', 
    Validators.compose(
     [Validators.minLength(5), Validators.required])); 

для асинхронных валидаторы использовать

this.username = new Control('', null, 
    Validators.composeAsync(
     [someAsyncValidator, otherAsyncValidator])); 

Есть открытые вопросы с асинхронными валидаторы, особенно синхронизироваться валидаторы в сочетании с асинхронными валидаторов не работают

Для того, чтобы синхронизировать валидаторы работать с асинхронными валидаторами, обернуть синхронизации валидаторов обещаний и составить их как асинхронное 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 
    ])); 
+1

Спасибо за это хорошее решение! Один вопрос: в чем разница между Validators.compose ([// myValidators]) и просто передачей валидаторов в качестве массива в качестве третьего параметра без Validators.compose()? – dave0688

+1

На самом деле нет разницы. Насколько я помню, просто передать их еще не удалось, когда я разместил этот ответ (по крайней мере, не для асинхронных валидаторов). –

+0

Отлично, спасибо за разъяснение этого! – dave0688

1

Я предлагаю с использованием методы Validators.compose() для комбинирования все неасинхронные валидаторы и отдельно передаются в Validators.composeAsync() для любых асинхронных вызовов.

В основном конструктор арга для FormControl является следующим:

  1. FormState (или просто начальное начального значения)
  2. валидаторов (я предлагаю использовать Validators.compose ([...]) здесь)
  3. asyncValidators (я предлагаю использовать Validators.composeAsync ([...]) здесь)

Пример использования FormBuilder (не стесняйтесь использовать прямо Control):

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) 
       ]) 
      ] 
     }); 

Это помогает избежать проверки асинхронной до тех пор пока не Асинхр валидаторы не являются допустимыми (не вкл. начальная проверка, которую можно легко обработать, см. ниже).

Все Совмещенный Пример (валидаторы, asyncValidators & дребезга):

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; 
    } 

} 

Некоторые люди любят, чтобы взломать в противодребезговой защите асинхронного валидатор путем связывания с наблюдаемым valueChanges элемента управления, как это:

this.someControl.debounceTime(300).subscribe(val => { 
     // async call... 
}); 

Я лично не рекомендую это для большинства случаев, так как он добавляет ненужных осложнений.

ПРИМЕЧАНИЕ: Это должно работать, как и в последней версии угловому (2 & 4), так как написания этого поста.

4

эта проблема была решена

вы можете создать массив валидаторов

this.username = new FormControl('', [ Validators.minLength(5), Validators.required ]); 
+1

В чем проблема с этим решением? –

Смежные вопросы