AJT_82 的回答对我非常有用,我想我会分享我如何重用他的代码并构建了一个类似的示例 - 一个可能有一个更常见的用例,即邀请几个人同时注册.像这样:
我认为这可能对其他人有帮助,所以我在这里添加它。
您可以看到表单是一个简单的电子邮件文本输入数组,每个都加载了一个自定义验证器。您可以在屏幕截图中看到 JSON 结构 - 查看模板中的前行(感谢 AJT),这是一个在开发过程中非常有用的想法,可查看您的模型和控件是否已连接!
首先,声明我们需要的对象。请注意,3 个空字符串是模型数据(我们将绑定到文本输入):
public form: FormGroup;
private control: FormArray;
private emailsModel = { emails: ['','','']} // the model, ready to hold the emails
private fb : FormBuilder;
构造函数是干净的(为了更容易测试,只需注入我的 userService 以在提交后发送表单数据):
constructor(
private _userService: UserService,
) {}
表单是在 init 方法中构建的,包括存储对 emailsArray 控件本身的引用,以便我们稍后检查其子项(实际输入)是否被触摸,如果是,它们是否有错误:
ngOnInit() {
this.fb = new FormBuilder;
this.form = this.fb.group({
emailsArray: this.fb.array([])
});
this.control = <FormArray>this.form.controls['emailsArray'];
this.patch();
}
private patch(): void {
// iterate the object model and extra values, binding them to the controls
this.emailsModel.emails.forEach((item) => {
this.control.push(this.patchValues(item));
})
}
这是使用验证器构建每个输入控件(AbstractControl 类型)的内容:
private patchValues(item): AbstractControl {
return this.fb.group({
email: [item, Validators.compose([emailValidator])]
})
}
检查输入是否被触摸以及验证器是否引发错误的 2 个辅助方法(请参阅模板以了解它们的使用方式 - 请注意,我从模板中的 *ngFor 传递数组的索引值) :
private hasError(i):boolean {
// const control = <FormArray>this.form.controls['emailsArray'];
return this.control.controls[i].get('email').hasError('invalidEmail');
}
private isTouched(i):boolean {
// const control = <FormArray>this.form.controls['emailsArray'];
return this.control.controls[i].get('email').touched;
}
这是验证器:
export function emailValidator(control: FormControl): { [key: string]: any } {
var emailRegexp = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$/;
if (control.value && !emailRegexp.test(control.value)) {
return { invalidEmail: true };
}
}
还有模板:
<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" class="text-left">
<div formArrayName="emailsArray">
<div *ngFor="let child of form.controls.emailsArray.controls; let i=index">
<div class="form-group" formGroupName="{{i}}">
<input formControlName="email"
class="form-control checking-field"
placeholder="Email" type="text">
<span class="help-block" *ngIf="isTouched(i)">
<span class="text-danger"
*ngIf="hasError(i)">Invalid email address
</span>
</span>
</div>
</div>
</div>
<pre>{{form.value | json }}</pre>
<div class="form-group text-center">
<button class="btn btn-main btn-block" type="submit">INVITE</button>
</div>
</form>
不管怎样,我一开始就是从这个糟糕的烂摊子开始的——但是如果你看看下面的代码,你可能会更容易理解上面的代码!
public form: FormGroup;
public email1: AbstractControl;
public email2: AbstractControl;
public email3: AbstractControl;
public email4: AbstractControl;
public email5: AbstractControl;
constructor(
fb: FormBuilder
) {
this.form = fb.group({
'email1': ['', Validators.compose([emailValidator])],
'email2': ['', Validators.compose([emailValidator])],
'email3': ['', Validators.compose([emailValidator])],
'email4': ['', Validators.compose([emailValidator])],
'email5': ['', Validators.compose([emailValidator])],
});
this.email1 = this.form.controls['email1'];
this.email2 = this.form.controls['email2'];
this.email3 = this.form.controls['email3'];
this.email4 = this.form.controls['email4'];
this.email5 = this.form.controls['email5'];
}
上面在模板中使用了其中的 5 个 div - 不是很干!
<div class="form-group">
<input [formControl]="email1" class="form-control checking-field" placeholder="Email" type="text">
<span class="help-block" *ngIf="form.get('email1').touched">
<span class="text-danger" *ngIf="form.get('email1').hasError('invalidEmail')">Invalid email address</span>
</span>
</div>