我有一个表格,我正在收集电话号码(手机,个人,其他)。我需要至少填充输入。我正在尝试使用Angular2 FormBuilder。
经过大量研究后,我遇到了解决这个问题的问题。我知道我可以使用其他方法来做到这一点,但我想知道是否可以使用FormBuilder验证器。如果我添加“Validators.required”,那么所有3个字段都是必需的。有什么建议或想法吗?
phone: this._fb.group(
{
other: [''],
personal: [''],
mobile: [''],
}
根据“JB Nizet”的提示,这是我必须实现的功能:
我的小组验证员(它仍然需要调整):
static phoneExists(group: FormGroup): { [key: string]: any } {
if (null != group) {
var other: AbstractControl = group.controls['other'];
var mobile: AbstractControl = group.controls['mobile'];
var personal: AbstractControl = group.controls['personal'];
var data: Object = group.value;
return (
(other.valid && isEmptyInputValue(other.value))
&& (mobile.valid && isEmptyInputValue(mobile.value))
&& (personal.valid && isEmptyInputValue(personal.value))
)
? { 'required': true }
: null;
}
}
我的小组改变了:
phone: this._fb.group(
{
other: [''],
personal: [''],
mobile: [''],
},
{ validator: MyValidators.phoneExists }
)
我花了一段时间,但关键是要添加关键字“验证器”,这将导致组验证器触发。
在HTML中我添加了以下内容:
<small *ngIf="!myForm.controls.profile.controls.phone.valid" class="text-danger">
At least one phone is required.
</small>
我希望这有助于其他任何人。
答案 0 :(得分:26)
我使用atLeastOne
函数创建基于任何现有验证器的自定义验证器:
import { FormGroup, ValidationErrors, ValidatorFn } from '@angular/forms';
export const atLeastOne = (validator: ValidatorFn) => (
group: FormGroup,
): ValidationErrors | null => {
const hasAtLeastOne =
group &&
group.controls &&
Object.keys(group.controls).some(k => !validator(group.controls[k]));
return hasAtLeastOne ? null : { atLeastOne: true };
};
美丽的是,您可以使用任何验证器,而不仅仅是Validators.required
。
在OP的情况下,它将被这样使用:
{
phone: this._fb.group({
other: [''],
personal: [''],
mobile: [''],
}, { validator: atLeastOne(Validators.required) })
}
答案 1 :(得分:8)
这是一个可以与每个FormGroup一起使用的通用代码:
export function AtLeastOneFieldValidator(group: FormGroup): {[key: string]: any} {
let isAtLeastOne = false;
if (group && group.controls) {
for (const control in group.controls) {
if (group.controls.hasOwnProperty(control) && group.controls[control].valid && group.controls[control].value) {
isAtLeastOne = true;
break;
}
}
}
return isAtLeastOne ? null : { 'required': true };
}
用法:
@Component({
selector: 'app-customers',
templateUrl: './customers.component.html',
styleUrls: ['./customers.component.scss']
})
export class CustomersComponent implements OnInit {
public searchCustomerForm: FormGroup;
constructor() { }
ngOnInit() {
this.searchCustomerForm = new FormGroup({
customerID: new FormControl(''),
customerEmail: new FormControl(''),
customerFirstName: new FormControl(''),
customerLastName: new FormControl('')
}, AtLeastOneFieldValidator);
}
}
答案 2 :(得分:0)
这是没有子组的表单的方法。它允许有一个字段验证器,而不是一组验证器。
const atLeastOneList = ['field2', 'field4', 'field5'];
this.form = this.fb.group({
field1: [''],
field2: ['', this.requiredAtLeastOne(atLeastOneList)],
field3: [''],
field4: ['', this.requiredAtLeastOne(atLeastOneList)],
field5: ['', this.requiredAtLeastOne(atLeastOneList)],
});
方法实现应该包含一个隐式保护 “超出最大调用堆栈大小”错误,因为我们要重新验证字段,需要避免递归。
requiredAtLeastOne(fields: string[]) {
return (control: FormControl) => {
// check if at least one field is set
const result = fields.some(name => {
const ctrl = control.parent.get(name);
return ctrl && ctrl.value && ctrl.valid;
});
// run at-least-one validator for other fields
Object.entries(control.parent.controls)
.filter(([name, ctrl]) =>
// here we are, proper filter prevents stack overflow issue
fields.includes(name) && ctrl !== control && !ctrl.valid && result
)
.forEach(([, ctrl]) => ctrl.updateValueAndValidity())
return !result ? { requiredAtLeastOne: true } : null;
};
};