Are there any methods to connect a projected template (ContentChild) to the form specified on the child, such as adding formControlName
after it has been rendered?
I am having difficulty in finding relevant information online, possibly due to using incorrect search terms.
Example without projection - currently functional
Below is an example of a form array linked to a control value accessor,
The component contains a form group with type
FormGroup<{ formArray: FormArray<{ formControl : FormControl }> }
however, when emitting value changes, only the array of values is sent i.e.
formValue.formArray.map(v => v.formControl)
So,
formArray
and formControl
are simply internal names within the component.
Specific example
<fieldset [formGroup]="formGroup">
<legend>Paving runs (minimum 1)</legend>
<ng-container formArrayName="formArray">
<fieldset *ngFor="let frmGrp of formGroup.controls.formArray.controls; let i = index">
<legend>Paving run</legend>
<ng-container [formGroup]="frmGrp">
<paving-run-form
formControlName="formControl">
</paving-run-form>
</ng-container>
<button (click)="remove(i)">Delete run</button>
</fieldset>
</ng-container>
<button (click)="add()">Add run</button>
</fieldset>
This structure is standard and effective, but I am now attempting to create a reusable component version.
My goal is to achieve something like this:
<generic-form-array formControlName="paved_runs" [labels]="labels">
<ng-template editMode>
<paving-run-form></paving-run-form>
</ng-template>
</generic-form-array>
In this case, 'labels' would be defined as follows:
@Input() labels: GenericFormArrayOptions = {
legendMany: "Paving runs (minimum 1)",
legendOne: "Paving run",
deleteOne: "Delete run",
addOne: "Add run",
}
Projected example - my attempted solution
<fieldset [formGroup]="formGroup">
<legend>{{ labels.legendMany }}</legend>
<ng-container formArrayName="formArray">
<fieldset *ngFor="let frmGrp of formGroup.controls.formArray.controls; let i = index">
<legend>{{ labels.legendOne }}</legend>
<ng-container [formGroup]="frmGrp">
<!-- project the form to edit one of array elements -->
<ng-container
[ngTemplateOutlet]="editModeTpl.templateRef">
</ng-container>
</ng-container>
<button (click)="remove(i)">{{ labels.deleteOne }}</button>
</fieldset>
</ng-container>
<button (click)="add()">{{ labels.addOne }}</button>
</fieldset>
The following is specified within the class:
@ContentChild(EditModeDirective) editModeTpl!: EditModeDirective
Here, the content is being projected correctly, however,
<paving-run-form></paving-run-form>
is not connected to the child form. Trying <paving-run-form formControlName="formControl"></paving-run-form>
does not work because it expects formControl
to be on the parent element instead.
Is there a way to render the component first and then attach it to the child form afterwards?