如何将投影模板(ContentChild)绑定到子组件表单并添加formControlName?
投影模板绑定子组件表单控件的可行方案
核心问题在于:内容投影的模板默认在父组件上下文中解析,直接使用formControlName会指向父组件的表单控件,而非子组件(generic-form-array)内部的FormArray。以下是两种贴合你场景的解决方案:
方案一:通过模板上下文传递子组件的FormGroup
利用ngTemplateOutletContext将子组件内部FormArray的单个FormGroup传递给投影模板,让投影内容能绑定到子组件的表单结构。
1. 改造generic-form-array组件模板
遍历内部FormArray时,将当前项的FormGroup通过上下文传给投影模板:
<!-- generic-form-array.component.html --> <div [formGroup]="formGroup"> <div formArrayName="formArray"> <div *ngFor="let itemGroup of formGroup.get('formArray')['controls']; let i = index" [formGroupName]="i" > <!-- 把当前FormGroup作为上下文传递给投影模板 --> <ng-container *ngTemplateOutlet="editModeTemplate; context: { $implicit: itemGroup }" ></ng-container> </div> </div> </div>
2. 在generic-form-array类中获取投影模板
// generic-form-array.component.ts import { Component, ContentChild, TemplateRef } from '@angular/core'; import { FormGroup, FormArray, FormControl } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ selector: 'generic-form-array', templateUrl: './generic-form-array.component.html', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: GenericFormArrayComponent, multi: true } ] }) export class GenericFormArrayComponent implements ControlValueAccessor { formGroup: FormGroup<{ formArray: FormArray<FormGroup<{ formControl: FormControl }>> }>; @ContentChild('editMode') editModeTemplate!: TemplateRef<any>; // 省略ControlValueAccessor实现和FormGroup初始化逻辑 // (保留你原有的值变更发射逻辑:formValue.formArray.map(v => v.formControl)) }
3. 父组件中使用投影模板
通过let-itemGroup接收子组件传递的FormGroup,绑定到paving-run-form:
<!-- 父组件模板 --> <generic-form-array [formControl]="parentFormControl"> <ng-template #editMode let-itemGroup> <!-- itemGroup是generic-form-array内部FormArray的单个FormGroup --> <paving-run-form [formGroup]="itemGroup"></paving-run-form> </ng-template> </generic-form-array>
4. paving-run-form内部绑定
直接使用formControlName绑定到子组件传递的FormGroup中的控件:
<!-- paving-run-form.component.html --> <div [formGroup]="formGroup"> <input formControlName="formControl" placeholder="输入内容" /> </div>
方案二:让投影组件直接接收FormControl
如果paving-run-form是实现了ControlValueAccessor的自定义表单控件,可以直接传递子组件内部的formControl给它:
1. 修改generic-form-array模板
传递单个formControl而非整个FormGroup:
<!-- generic-form-array.component.html --> <div [formGroup]="formGroup"> <div formArrayName="formArray"> <div *ngFor="let itemGroup of formGroup.get('formArray')['controls']; let i = index" [formGroupName]="i" > <ng-container *ngTemplateOutlet="editModeTemplate; context: { $implicit: itemGroup.get('formControl') }" ></ng-container> </div> </div> </div>
2. 父组件使用方式
<generic-form-array [formControl]="parentFormControl"> <ng-template #editMode let-formControl> <paving-run-form [formControl]="formControl"></paving-run-form> </ng-template> </generic-form-array>
这种方式下,paving-run-form无需关心外部表单结构,只需处理自身的formControl值即可。
内容的提问来源于stack exchange,提问作者Andrew Allen
相关产品推荐
相关产品推荐

