Managing dynamic components

bergermarko

Marko Berger

Posted on September 7, 2019

Managing dynamic components

Coders beware

Here there be monsters

Last time I have posted the article about dynamic components in Angular. Demonstrated how to set up one. Now here these a warning.
If you pass some kind of subject (behavior or any other) to your dynamic component and you passed it to your entry component (component you actually want to load). You will find your self in trouble.

What are you talking about!?

The example I have demonstrated is perfectly fine. It is clean and has no subscriptions. But when we have a subscription. We need to unsubscribe. Right!
Where do we do unsubscribing? NgOnDestroy.
And there is a problem.
By changing between components NgOnDestroy hook does not fire. That's because we are not destroying the entry component. We are replacing it.

What!!!

Now our app has gone bananas.
Our subscription lives on and if you fire the same event for your all entry component you are in trouble. There are no error messages and the application is showing weird results.

So what do we need to do?

We need to destroy our entry component.

 componentRef: ComponentRef<any>; //declaration 
 this.componentRef.destroy();
Enter fullscreen mode Exit fullscreen mode

This will destroy the component and fire the NgOnDestroy hook.
Example of the code

 loadComponent(){
    if(this.componentRef){
    /** Checkig if an old component reference exists and then we destroy it*/ 
      this.componentRef.destroy();
    }
    /** Preparing our component for creation */
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.components[this.inputData]);
    /** Grabbing reference of our view placeholder */
    const viewContainerRef = this.placeholder.viewContainerRef;
    /** Clearing our placeholder  */
    viewContainerRef.clear();
    /** Magic of creating a component instance  */
    this.componentRef = viewContainerRef.createComponent(componentFactory);
    /** 
     * @Input data into our instance.
     */
    (this.componentRef.instance as IComp).text = ''+this.inputData;
    /** @Output data from our instance  */
    (this.componentRef.instance as IComp).event.subscribe(
      data => this.changeEmit.emit(data)
    );
  }
Enter fullscreen mode Exit fullscreen mode

I have updated git repo with this code. You can find the link at the end of this article

Lessons learned

Mistakes have the power to turn you into something better than you were before.

Github Repo

DynamicExample

This project was generated with Angular CLI version 7.3.7.

Development server

Run ng serve for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.

Code scaffolding

Run ng generate component component-name to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module.

Build

Run ng build to build the project. The build artifacts will be stored in the dist/ directory. Use the --prod flag for a production build.

Running unit tests

Run ng test to execute the unit tests via Karma.

Running end-to-end tests

Run ng e2e to execute the end-to-end tests via Protractor.

Further help

To get more help on the Angular CLI use ng help or go check out the Angular CLI README.






💖 💪 🙅 🚩
bergermarko
Marko Berger

Posted on September 7, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related