Currently, I am working on defining a Component that consists of a dynamic Form using ReactiveForms. The goal is to allow users to add or delete Controls within the form. These Controls can vary in structure and need to be defined externally to the Component. This is why I believe that TemplateRef would be the most suitable approach for this scenario.
My main challenge lies in connecting the externally defined Control to the internal Form using formControlName.
Below is the initial implementation:
// expandable.component.ts
[...]
@Component({
selector: 'expandable',
templateUrl: 'app/component/common/expandable/expandable.component.html',
styleUrls: ['app/component/common/expandable/expandable.component.css']
})
export class ExpandableComponent {
@ContentChild('childTemplate') childTemplate: TemplateRef<any>;
@Input() children: Array<any>;
public form: FormGroup;
constructor(private _changeDetector: ChangeDetectorRef,
private _formBuilder: FormBuilder) {
this.children = [];
}
public ngOnInit(): void {
this.form = this._formBuilder.group({
children: this._formBuilder.array([])
});
const arrayControl = <FormArray>this.form.controls['children'];
this.children.forEach(child => {
const group = this.initChildForm();
arrayControl.push(group);
});
}
private initChildForm(): AbstractControl {
return this._formBuilder.group({
key: ['Initial Key', [Validators.required]],
value: ['Initial Value', [Validators.required]]
});
}
public addChild(): void {
const control = <FormArray>this.form.controls['children'];
control.push(this.initChildForm());
this._changeDetector.detectChanges();
}
}
-
<!-- expandable.component.html -->
<form [formGroup]="form">
<div class="form-group">
<div formArrayName="children">
<div *ngFor="let child of form.controls.children.controls; let i=index">
<div [formGroupName]="i">
<template
[ngTemplateOutlet]="childTemplate"
[ngOutletContext]="{ $implicit: child }"></template>
</div>
</div>
</div>
</div>
<a (click)="addChild()">Add Child</a>
</form>
Attempting to define the template externally:
<expandable>
<template #childTemplate>
<input class="form-control"
formControlName="value" />
</template>
</expandable>
I have attempted to bind the formControlName to the context passed from the outer , but unfortunately, I keep receiving an error "Cannot find control with name: 'value'". Ideally, I would prefer to handle the formControlName binding within the expandable.component.html file, but I haven't found a way to accomplish this either. Any insights or suggestions would be greatly appreciated.