Tim Hardy
Tim Hardy

Reputation: 1737

Angular Dynamic Component Creation not rendering dynamic child components

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

Upvotes: 1

Views: 1399

Answers (2)

yurzui
yurzui

Reputation: 214077

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);

Forked Stackblitz

Another option

When working with dynamically creating forms you don't need to wrap all your ng-templates 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 class="child-questions">
  <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.

Forked Stackblitz 2

Upvotes: 2

chrisonstack
chrisonstack

Reputation: 1

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.

Upvotes: 0

Related Questions