7
votes

I am developing an Ionic + Angular 5 project.

I need to dynamically load some components. Following the Dynamic Component Loader Example in the Angular documentation I am able to successfully load components and displayed them.

I have a need, however, to be able to loop through the loaded components.

I can easily maintain my own list of components in the parent as I create and destroy the child components but it seems to me that that's ugly and not the "Angular Way".

After much experimentation and research it seems that I cannot use @ViewChildren to access dynamically added components since they have their own views. ViewChildren not finding Dynamically components

Is this correct?

I am able to use viewContainerRef.get() to iterate over the child views and retrieve ViewRefs. But there doesn't seem to be a way to get a reference to the component given a ViewRef?

I notice the 'rootNodes' property of the ViewRef however that property is not documented in the Angular docs View Ref However, it is documented in the EmbeddedViewRef docs Embedded View Ref but that still doesn't seem to give me access to the component.

So the question is when I have a parent that dynamically adds child components how can I from the parent loop through the child components (so I can call one of my methods in the child)? My suspicion is that I am missing something stupid simple, have some fundamental misconception, or that there is a different pattern that I should be using.

I've modified the Dynamic Component Loader example to highlight what I am trying to do.Modified Dynamic Component Loader

1
I'm just wondering why not store created component in a member and use it later, like let componentRef = viewContainerRef.createComponent(componentFactory); this.newComponent = componentRef; and then in logViewChildren() do console.log(this.newComponent.instance.data);? - pwwpche
Yea, that's my fallback which I'm implementing at the moment. My intent is to try to understand Angular thinking. It seems to me it should be possible without having to keep a separate stack of components, but maybe I am mistaken. - Yermo Lamers
Its the angular way that that dynamic components should communicate by a shared service hosted on the parent and injected on the child. I personally find managing the ref.instance to be perfectly fine. (your backup solution) - Nuno Sousa
@pwwpche Your recommendation is great. Very simple and keeps the code easy to follow and maintain going forward. - tonejac

1 Answers

2
votes

So, I thought about this and a clean way to do this (in my opinion), is to pass create a property on the parent component, such as parentContext and to pass the data or method into this object.

Example - in parent component, you can even pass a method into your child component and it will run within the context of the parent.:

  gotoDetail(hero: Hero): void {
    this.entry.clear();
    const factory = this.resolver.resolveComponentFactory(DynamicModalChildComponent);
    this.dynamicModalComponentRef = this.entry.createComponent(factory);
    this.dynamicModalComponentRef.instance.hero = hero;
    // Pass parent context to child in order to close modal hierarchically (parent/child component relationship).
    // This approach is less verbose and makes it easier to unit test than a service in my opinion.
    this.dynamicModalComponentRef.instance.parentContext = () => this.destroyComponent();
}