Я предлагаю с использованием методы Validators.compose() для комбинирования все неасинхронные валидаторы и отдельно передаются в Validators.composeAsync() для любых асинхронных вызовов.
В основном конструктор арга для FormControl является следующим:
- FormState (или просто начальное начального значения)
- валидаторов (я предлагаю использовать Validators.compose ([...]) здесь)
- 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), так как написания этого поста.
Спасибо за это хорошее решение! Один вопрос: в чем разница между Validators.compose ([// myValidators]) и просто передачей валидаторов в качестве массива в качестве третьего параметра без Validators.compose()? – dave0688
На самом деле нет разницы. Насколько я помню, просто передать их еще не удалось, когда я разместил этот ответ (по крайней мере, не для асинхронных валидаторов). –
Отлично, спасибо за разъяснение этого! – dave0688