I am building an angular application. A list of child controls will be dynamicly built based on the conditions in the parent control.
The dynamic control is embedded in the parent form:
<app-dynamic-form [searchItem]="searchItemValue"></app-dynamic-form>
Here is the code for the form setup:
//form group setup
this.searchForm = this.fb.group({
category: this.fb.control('', [Validators.required]),
searchItem: this.fb.control({ value: '', disabled: true }, [Validators.required]),
dynamicFormArray: this.fb.array([])
});
A BehaviorSubject and JSON are used for the communication between the parent and the child dynamic component.
private subjectFormFields = new BehaviorSubject({} as DynamicFormFieldModel[]);
currentFormFields = this.subjectFormFields.asObservable();
dynamicFormFields!: DynamicFormFieldModel[] =
[
{
id: 'firstName',
label: 'First Name',
type: 'text',
value: ''
},
...
]
updateFormFieldList(formFieldList: DynamicFormFieldModel[]) {
this.subjectFormFields.next(formFieldList);
}
In the dynamic form component, the dynamic contorls are built like this:
updateDynamicForm() {
this.dynamicFormArray.clear();
//Dynamicly create form field controls and add it to the parent form
this.dynamicFormFields.forEach(formItem => {
const form = this.fb.group([]);
const formControl = this.fb.control('', formItem.validators);
form.addControl(formItem.id, formControl);
this.dynamicFormArray.push(form);
})
}
In the dynamic component, I have everything setup with reqired formGroupName and formControlName (which seems a source to have the same error acoording to the web research):
<ng-container formArrayName="dynamicFormArray" *ngIf="(dynamicFormFields && dynamicFormFields.length)">
<ng-container *ngFor="let formItem of dynamicFormFields; let i = index;">
<div >
<label>{{formItem.label}}</label>
<ng-container [ngSwitch]="formItem.type">
<!-- Input Text-->
<ng-container [formGroupName]="i" *ngSwitchCase="'text'">
<input type="text"
[formControlName]="formItem.id" [id]="formItem.id">
</ng-container>
...
</ng-container>
</div>
</ng-container>
</ng-container>
However, I still get "Cannot find control with path" error from time to time but not always. Why?
I googled searched "Cannot find control with path" and made sure that the formArrayName, formGroupName and formControlName are all correctly in place. and check the form building process ..
CodePudding user response:
In general it's always better iterate over the formArray.controls (use the index to get the values of the dynamicFormFields)
<ng-container formArrayName="dynamicFormArray" *ngIf="(dynamicFormFields && dynamicFormFields.length)">
<!--see iterate over dynamicFormArray.controls-->
<ng-container *ngFor="let group of dynamicFormArray.controls; let i = index;">
<!--then use dynamicFormFields[i] instead of formItem-->
<div >
<label>{{dynamicFormFields[i].label}}</label>
<ng-container [ngSwitch]="dynamicFormFields[i].type">
<!-- Input Text-->
<ng-container [formGroupName]="i" *ngSwitchCase="'text'">
<input type="text"
[formControlName]="dynamicFormFields[i].id" [id]="dynamicFormFields[i].id">
</ng-container>
...
</ng-container>
</div>
</ng-container>
</ng-container>
CodePudding user response:
Finally we found the problem was that the updateDynamicForm method was not always implemented because it was put in ngOnChanges() event handler of the dynamic component. Moving it to ngOnInit() had the problem resolved.
It seems this "Cannot find control with path" error is one of the common problem in the dynamicly built form in Angular. Here are some key points that I think when building dynamic form:
- initial setup the form: dynamicFormArray: this.fb.array([])
- make sure formArrayName, formGroupName and formControlName are in place
- make sure the dynamic update (or rebuilt) menthod is called inside ngOnInit().
Thank you and hope it will help someone who are having similar problem. Thanks to other peopl who have posted solutions which have helped me in differet ways.