In my Angular 12 app I have this type of hierarchy:
- app.component
-- Parent component with form (reactive)
--- Component that creates the dynamic components
---- Dynamic component
and my formBuilder form looks like this:
form = this.fb.group({
baseLevelControl: ["base control"],
groupOfGroups: [this.fb.group({
innerGroup1: this.fb.group({
dummy1Control1: "control 1 from inner group 1",
dummy1Control2: "control 2 from inner group 1",
}),
innerGroup2: this.fb.group({
dummy2Control1: "control 1 from inner group 2",
dummy2Control2: "control 2 from inner group 2",
}),
})]
});
My dynamic component only needs to know about the groupOfGroups and not the whole form because it will be used in many places with different kinds of forms.
When I set in the dynamic component
<div [formGroup]="innerForm">
I get a seperate independent form that does not communicate with parent form. If I use
<div formGroupName="innerForm">
I get error that formGroupName must be used with a parent formGroup directive
How can I properly bind the groupOfGroups?
I've create this stackblitz project to emulate the issue, any help would be much appreciated
CodePudding user response:
You can inject ControlContainer
in your child components to get access to the parent components form group.
In your child dynamic1.component.ts
component, inject ControlContainer and assign the parent form group to the child component's FormGroup
property. This will give you access to the parent FormGroup
from the parent component.
@Component({
selector: 'app-dynamic1',
templateUrl: './dynamic1.component.html',
styleUrls: ['./dynamic1.component.scss'],
})
export class Dynamic1Component implements OnInit {
public formGroup: FormGroup;
constructor(private _parentContainer: ControlContainer) {}
ngOnInit(): void {
this.formGroup = this._parentContainer.control as FormGroup;
}
}
Update your dynamic1.component.html
to use this form group.
<div *ngIf="formGroup" [formGroup]="formGroup">
<div formGroupName="innerGroup1">
<p>dummy controls for group 1</p>
<input formControlName="dummy1Control1" />
<input formControlName="dummy1Control2" />
</div>
<div formGroupName="innerGroup2">
<p>dummy controls for group 2</p>
<input formControlName="dummy2Control1" />
<input formControlName="dummy2Control2" />
</div>
</div>
In your level1.component.ts
update the FormGroup. You originally had the groupOfGroups
as an array. This is not needed, you can simply just assign a FormGroup to this.
@Component({
selector: 'app-level1',
templateUrl: './level1.component.html',
styleUrls: ['./level1.component.scss'],
})
export class Level1Component implements OnInit {
form = this.fb.group({
baseLevelControl: ['base control'],
groupOfGroups: this.fb.group({
innerGroup1: this.fb.group({
dummy1Control1: 'control 1 from inner group 1',
dummy1Control2: 'control 2 from inner group 1',
}),
innerGroup2: this.fb.group({
dummy2Control1: 'control 1 from inner group 2',
dummy2Control2: 'control 2 from inner group 2',
}),
}),
});
// OTHER STUFF....
}
And your level1.component.html
template would look like...
<h1>Level 1</h1>
<div [formGroup]="form">
<label for="baseControl">Base Control Value:</label>
<input name="baseControl" formControlName="baseLevelControl" type="text" />
<div formGroupName="groupOfGroups">
<h3>Dynamic 2</h3>
<app-dynamic1></app-dynamic1>
</div>
<div>
<button type="button" (click)="onSubmit()">Submit</button>
</div>
</div>