如何在 Angular2 中为表单分配和验证数组
How to assign and validate arrays to forms in Angular2
我在 javascript 中的模型 (this.profile
) 有一个名为 emails
的 属性,它是 {email, isDefault, status}
的数组
然后我定义如下
this.profileForm = this.formBuilder.group({
.... other properties here
emails: [this.profile.emails]
});
console.log(this.profile.emails); //is an array
console.log(this.profileForm.emails); // undefined
在html文件中我用它作为
<div *ngFor="let emailInfo of profileForm.emails">
{{emailInfo.email}}
<button (click)="removeEmail(emailInfo)">
Remove
</button>
</div>
如果我不将它添加到 formGroup
中并将其用作数组 - 如下所示 - 它工作正常,但我有一个业务规则,这个数组不应该为空,我是无法根据 this
的长度设置表单验证
emails : [];
this.profileForm = this.formBuilder.group({
.... other properties here
});
this.emails = this.profile.emails;
console.log(this.profile.emails); //is an array
console.log(this.emails); // is an array
我也试过使用 formBuilder.array
但那个是用于控制数组而不是数据数组。
emails: this.formBuilder.array([this.profile.emails])
那么我的问题是我应该如何将数组从模型绑定到 UI 以及我应该如何验证数组的长度?
这对我有用 (angular 2.1.2),这种方法让您可以灵活地为您的电子邮件定义自定义验证:
this.profileForm = this.formBuilder.group({
emails: [this.profile.emails, FormValidatorUtils.nonEmpty]
// ......
});
export class FormValidatorUtils {
static nonEmpty(control: any) {
if (!control.value || control.value.length === 0) {
return { 'noElements': true };
}
return null;
}
}
How should I bind an array from model to UI?
好吧,我宁愿将所有 电子邮件 从 profile.emails
推送到 formArray
,否则您将拥有这些值,但没有验证。
How should I validate the length of array?
您可以像使用任何其他 控件一样使用 Validators.minLength(Number)
。。
演示代码:
分量:
export class AnyComponent implements OnInit {
profileForm: FormGroup;
emailsCtrl: FormArray;
constructor(private formBuilder: FormBuilder) { }
ngOnInit(): void {
this.emailsCtrl = this.formBuilder.array([], Validators.minLength(ANY_NUMBER));
this.profile.emails.forEach((email: any) => this.emailsCtrl.push(this.initEmail(email)));
this.profileForm = this.formBuilder.group({
// ... other controls
emails: this.emailsCtrl
});
}
private initEmail = (obj: any): FormGroup => {
return this.formBuilder.group({
'email': [obj.email], //, any validation],
'isDefault': [obj.isDefault] //, any validation]
});
}
}
模板:
<div *ngFor="let emailInfo of emailsCtrl.value">
{{emailInfo.email}}
<button (click)="removeEmail(emailInfo)">
Remove
</button>
</div>
<div *ngIf="emailsCtrl.hasError('minlength')">
It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
</div>
PS1:注意Validators.minLength(param)
method的param必须大于1,否则不会验证。
正如您在 source 中看到的那样,当 控件 为空时,它会自动 returns null。
然后,要使其按预期工作,您可以添加 required
Validator:
this.emailsCtrl = this.formBuilder.array([], Validators.compose([Validators.required, Validators.minLength(ANY_NUMBER > 1)]);
并在模板中:
<div *ngIf="emailsCtrl.invalid">
<span *ngIf="emailsCtrl.hasError('required')">
It's required
</span>
<span *ngIf="emailsCtrl.hasError('minlength')">
It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
</span>
</div>
PS2:
我认为在 removeEmail
函数 中传递要删除的电子邮件的索引更有意义,这样您就不必调用 indexOf
获取 specific email
的索引。你可以这样做:
<div *ngFor="let emailInfo of emailsCtrl.value; let i = index">
{{emailInfo.email}}
<button (click)="removeEmail(i)">
Remove
</button>
</div>
分量:
removeEmail(i: number): void {
this.emailsCtrl.removeAt(i);
}
看看这个简单的DEMO
我在 javascript 中的模型 (this.profile
) 有一个名为 emails
的 属性,它是 {email, isDefault, status}
然后我定义如下
this.profileForm = this.formBuilder.group({
.... other properties here
emails: [this.profile.emails]
});
console.log(this.profile.emails); //is an array
console.log(this.profileForm.emails); // undefined
在html文件中我用它作为
<div *ngFor="let emailInfo of profileForm.emails">
{{emailInfo.email}}
<button (click)="removeEmail(emailInfo)">
Remove
</button>
</div>
如果我不将它添加到 formGroup
中并将其用作数组 - 如下所示 - 它工作正常,但我有一个业务规则,这个数组不应该为空,我是无法根据 this
emails : [];
this.profileForm = this.formBuilder.group({
.... other properties here
});
this.emails = this.profile.emails;
console.log(this.profile.emails); //is an array
console.log(this.emails); // is an array
我也试过使用 formBuilder.array
但那个是用于控制数组而不是数据数组。
emails: this.formBuilder.array([this.profile.emails])
那么我的问题是我应该如何将数组从模型绑定到 UI 以及我应该如何验证数组的长度?
这对我有用 (angular 2.1.2),这种方法让您可以灵活地为您的电子邮件定义自定义验证:
this.profileForm = this.formBuilder.group({
emails: [this.profile.emails, FormValidatorUtils.nonEmpty]
// ......
});
export class FormValidatorUtils {
static nonEmpty(control: any) {
if (!control.value || control.value.length === 0) {
return { 'noElements': true };
}
return null;
}
}
How should I bind an array from model to UI?
好吧,我宁愿将所有 电子邮件 从 profile.emails
推送到 formArray
,否则您将拥有这些值,但没有验证。
How should I validate the length of array?
您可以像使用任何其他 控件一样使用 Validators.minLength(Number)
。。
演示代码:
分量:
export class AnyComponent implements OnInit {
profileForm: FormGroup;
emailsCtrl: FormArray;
constructor(private formBuilder: FormBuilder) { }
ngOnInit(): void {
this.emailsCtrl = this.formBuilder.array([], Validators.minLength(ANY_NUMBER));
this.profile.emails.forEach((email: any) => this.emailsCtrl.push(this.initEmail(email)));
this.profileForm = this.formBuilder.group({
// ... other controls
emails: this.emailsCtrl
});
}
private initEmail = (obj: any): FormGroup => {
return this.formBuilder.group({
'email': [obj.email], //, any validation],
'isDefault': [obj.isDefault] //, any validation]
});
}
}
模板:
<div *ngFor="let emailInfo of emailsCtrl.value">
{{emailInfo.email}}
<button (click)="removeEmail(emailInfo)">
Remove
</button>
</div>
<div *ngIf="emailsCtrl.hasError('minlength')">
It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
</div>
PS1:注意Validators.minLength(param)
method的param必须大于1,否则不会验证。
正如您在 source 中看到的那样,当 控件 为空时,它会自动 returns null。
然后,要使其按预期工作,您可以添加 required
Validator:
this.emailsCtrl = this.formBuilder.array([], Validators.compose([Validators.required, Validators.minLength(ANY_NUMBER > 1)]);
并在模板中:
<div *ngIf="emailsCtrl.invalid">
<span *ngIf="emailsCtrl.hasError('required')">
It's required
</span>
<span *ngIf="emailsCtrl.hasError('minlength')">
It should have at least {{emailsCtrl.getError('minlength').requiredLength}} emails
</span>
</div>
PS2:
我认为在 removeEmail
函数 中传递要删除的电子邮件的索引更有意义,这样您就不必调用 indexOf
获取 specific email
的索引。你可以这样做:
<div *ngFor="let emailInfo of emailsCtrl.value; let i = index">
{{emailInfo.email}}
<button (click)="removeEmail(i)">
Remove
</button>
</div>
分量:
removeEmail(i: number): void {
this.emailsCtrl.removeAt(i);
}
看看这个简单的DEMO