正如标题所说,为了类型安全和简洁性,我最终选择使用formControl 指令来代替 formControlName。
类型安全
给定这个formGroup:
formGroup = this.formBuilder.group({
booker: "",
bookNames: this.formBuilder.array([new FormControl("", Validators.required)]),
});
使用formControlName的HTML可能是这样的:
<div [formGroup]="formGroup">
<input
[placeholder]="'please enter the booker name'"
formControlName="booker"
/>
<ng-container formArrayName="bookNames">
<input [placeholder]="'please enter the book name'" formControlName="0" />
</ng-container>
</div>
到目前为止,如果字段名booker、bookNames或0中有拼写错误,在编辑器中您不会看到任何错误。只有在运行时才会看到错误,例如ERROR Error: Cannot find control with name: 'booker1'。
然而,当不正确地绑定formControl时,由于它是TypeScript,您会立即在编辑器中看到类似Property 'booker1' does not exist on type '的错误。
<div>
<input
[placeholder]="'please enter the booker name'"
[formControl]="formGroup.controls.booker"
/>
<input
[placeholder]="'please enter the book name'"
[formControl]="formGroup.controls.bookNames.at(0)"
/>
</div>
类型检查对您有很大帮助,尤其是在重命名字段名时。
简洁性
基于上面的例子,您可以看到我们不需要formGroup或formArrayName来与formControl一起工作。但是当我们使用formControlName指令时,我们需要它们。在这个例子中这不是大问题。
假设您想要将formGroup.controls.bookNames.at(0)移动到子组件中。使用formControl指令,您只需要@Input() formCtrl!: FormControl<string | null>;即可使其工作。完整代码如下所示:
@Component({
selector: "app-item",
imports: [FormsModule, ReactiveFormsModule],
template: `
<input
[placeholder]="'please enter the book name'"
[formControl]="formCtrl"
/>
`,
styles: ``,
})
export class ItemComponent {
@Input() formCtrl!: FormControl<string | null>;
}
以及
<div>
<input
[placeholder]="'please enter the booker name'"
[formControl]="formGroup.controls.booker"
/>
<app-item [formCtrl]="formGroup.controls.bookNames.at(0)"> </app-item>
</div>
可以看到所需的努力和更改都很小。
而使用formControlName,则需要@Input() formGroup!: FormGroup<any>;、@Input() formArrayName!: string;和@Input() formCtrlName!: string;才能使其工作。完整代码如下:
@Component({
selector: "app-item",
imports: [FormsModule, ReactiveFormsModule],
template: `
<ng-container [formGroup]="formGroup">
<ng-container [formArrayName]="formArrayName">
<input
[placeholder]="'please enter the book name'"
[formControlName]="formCtrlName"
/>
</ng-container>
</ng-container>
`,
styles: ``,
})
export class ItemComponent {
@Input() formGroup!: FormGroup<any>;
@Input() formArrayName!: string;
@Input() formCtrlName!: string;
}
<div [formGroup]="formGroup">
<input
[placeholder]="'please enter the booker name'"
formControlName="booker"
/>
<app-item
[formCtrlName]="'0'"
[formArrayName]="'bookNames'"
[formGroup]="formGroup"
>
</app-item>
</div>
如您所见,这样做看起来并不聪明。
实际上,ItemComponent可以仅用formControlName工作,但在这种情况下,ItemComponent需要实现ControlValueAccessor,这不是很简单,并带来了额外的复杂性。