We've built a rather fancy dynamic component creation framework to build out complex forms based on json data. We have components that get created via
const questionComponent = FieldComponentMap[childField.shortName];
viewContainerRef.createComponent<QuestionComponent>(questionComponent);
Those components may create child components of their own, etc, etc. It's all very elegant, and we like the design. We've got the whole thing "working", but it's not working well. Child, or perhaps grandchild components often don't render the first time around until something changes on the page. I'm sure we're just missing something simple, but we could use some more eyes to help us find what we're doing wrong.
We've tried moving all the dynamic component creation out of ngOnInit and into ngAfterContentInit, but that didn't help. We obviously want the complete form to render immediately.
Here's a StackBlitz demonstrating our issue (drastically simplified from our framework)... StackBlitz
CodePudding user response:
I think you're lost in the hierarchy.
To be more precisely, you're operating a wrong instance of FormGroup
in
array-question-wrapper.component.ts
Try replacing
this.createChildQuestionComponents(this.formGroup);
with
this.createChildQuestionComponents(this.formGroup.get(
[this.formArrayName, this.formArrayIndex]) as FormGroup);
Another option
When working with dynamically creating forms you don't need to wrap all your ng-template
s with formGroup
, formArrayName
directives. They are not tied to your child dynamically created controls anyway.
So:
parent-array-question.component.ts
Replace
componentRef.instance.containingControl = this.formGroup;
with
componentRef.instance.containingControl = arrayItem;
array-question-wrapper.component.ts
template should be:
<div >
<ng-template appQuestionHost></ng-template>
</div>
or just <ng-template appQuestionHost></ng-template>
if you don't need any additional classes here or you can use host element to style it.
CodePudding user response:
I had issues with template portals that were instantiated within a component that was dynamically added. Setting a timeout to associate the template portal within the dynamically created component fixed it. I am not perfectly satisfied with that. But, it may give a hint as to why your controls are not being recognised.