Reputation: 1648
I'm creating a project with a Reactive Form
; based on Recursive
Component that creates Dynamic Form
from JSON
file.
The Sources
I Adapted the Recursive version procedures and other changes!
My code is located in Stackblitz.
I will show a reduced code version of json-form.component.html file:
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<div fxLayout="column">
<ng-container *ngFor="let control of jsonFormData?.controls">
<div fxFlex="100%">
<selects
*ngIf="control.type === 'select'"
[control]="control"
[visible]="true"
></selects>
</div>
</ng-container>
</div>
<button mat-raised-button class="mt-1" color="primary">
<em class="fa fa-save">Submit</em>
</button>
</form>
As you can see the custom component is selects
.
Now, let's take a look at the Recursive
code of use of the selects
template. Again I reduce the code of select.component.html file:
<form [formGroup]="form">
<ng-container *ngIf="control?.children">
<mat-form-field
*ngIf="control.type === 'select' && control.visible"
fxFlex="100%"
hideRequiredMarker
>
<mat-label>{{ control.label }}</mat-label>
<mat-select
[formControlName]="control.name"
[placeholder]="control.label"
(selectionChange)="onSelectChange($event.value)"
>
<mat-option
*ngFor="let child of control.children"
[value]="child.value"
>
{{ child.label }}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<ng-container *ngFor="let child of control?.children">
<div fxFlex="100%">
<selects *ngIf="child.type === 'select'" [control]="child"></selects>
</div>
</ng-container>
</form>
The code of recursion using selects
Component is:
<ng-container *ngFor="let child of control?.children">
<div fxFlex="100%">
<selects *ngIf="child.type === 'select'" [control]="child"></selects>
</div>
</ng-container>
An example of error is:
ERROR
Error: Cannot find control with name: 'Petitioner (C2 -> P2)'
Unfortunately, I can't to find the problem in order to solve it.
Some clue in order to solve the error?
EDIT I suspect that not all components are shown inmediately, only when the Select is clicked; then the component is not still created.
Upvotes: 2
Views: 2336
Reputation: 1648
As you can see in the displayed view, all the FormControl
are there.
But, when a click event is presented. I show the all FormControl
's of my Form
in that istant with the line: console.log(this.form.value);
As you can see in the Green
bottom right rectangle in.
In the last Event. Only appears two controls!!!!, But are shown 7 formControls without button!...
Then my Form (variable this.form
) need to add those FormControl's.
How to do that?
First, I need to obtain the main Form
and FormGroup
(of my parent Component).
In my parent component (JsonFormComponent
) from the json-form.component.ts file:
export class JsonFormComponent implements OnChanges {
@Input() jsonFormData: JsonFormData;
public myForm: FormGroup = this.fb.group({});
public myFormBuilder: FormBuilder;
constructor(private fb: FormBuilder) {
this.myFormBuilder = fb;
}
Now, I have public
myForm
: FormGroup...
and public
myFormBuilder
: FormBuilder;
for my parent Component!.
The next step, is create local variable in each child-component located in the selects.component.ts file.
export class SelectsComponent implements OnInit {
public form: FormGroup;
@Input() formBuilder: FormBuilder;
constructor(private rootFormGroup: FormGroupDirective) {}
ngOnInit(): void {
this.form = this.rootFormGroup.form;
}
Now, I have public
form
: FormGroup...
and @Input()
formBuilder
: FormBuilder;
for my child Component!.
The next step, is to pass that objects to my child-components:
The solution in order to pass (or relate) myForm
(FormGroup
) comes from this post.
But, the relation for myFormBuilder
is done in the json-form.component.html file.
<selects
*ngIf="control.type === 'select'"
[control]="control"
[visible]="true"
(addControl)="onAddControl($event)"
[formBuilder]="myFormBuilder"
></selects>
Specifically in the line: [formBuilder]="myFormBuilder"
.
And for the recursion, in the selects.component.html file
<ng-container *ngFor="let child of control?.children">
<div fxFlex="100%">
<selects
*ngIf="child.type === 'select'"
[control]="child"
[formBuilder]="formBuilder"
></selects>
</div>
</ng-container>
Specifically in the line: [formBuilder]="formBuilder"
.
Now, in my child-component in the file selects.component.ts I created this method:
private newControl(control: JsonFormControls) {
this.form.addControl(
control.name,
this.formBuilder.control(control.value, getValidators(control))
);
control.visible = true;
}
Lastly: I changed my method, in order to add the FormControl
that needs to be displayed:
public onSelectChange(event: MatSelectChange) {
console.log(this.form.value);
this.control.value = event + '';
if (this.control.children) {
this.recursiveConcealer(this.control.children);
const child = this.control.children.find(
(child) => child.value === event + ''
);
this.newControl(child);
if (child.siblings) {
for (let sibling of child.siblings) {
this.newControl(sibling);
}
}
}
}
Note specifically the lines: this.newControl(child);
and this.newControl(sibling);
.
As you can see in the Blue
rectangle, the errors are gone.
NOTE: Theres is not the only one solution, here a question How can I pass the FormGroup of a parent component to its child component using the current Form API about this subject.
Upvotes: 0