Search code examples
angulartypescriptangular-materialcomponentsangular-dynamic-components

Best Way To Add Angular Component At RunTime On Click Event


The website I am building has multiple components. On the "Home" page component, when a user clicks a button to add something to the page, I want to append the component of their choice to the "home" component. I have researched and found 3 ways of doing this, but I want to know what is the best practice considering for such a feature. The page will be initialized with some components already added by other users. I want users to be able to add to the components on there.

Angular says I should do it this way: https://angular.io/guide/dynamic-component-loader

Angular Material says I should do it this way: https://material.angular.io/cdk/portal/overview

And I personally was expecting to it this way (which works) but I do not think it is a "best practice":

So when a user clicks on this tag it would fire the append method:

<a class="dropdown-item" href="#!" (click)="prependMedia('elementOne')">ElementOne</a>

That method calls this in the TS file of the component, effectively pushing a new element to an array. Then the HTML listed will watch for a new element added and put the component into the ngFor:

TypeScript File:

mediaElements: any[] = [];
  element: any = {
    name: 'elementOne',
    data: 'data'
};

constructor() { }

ngOnInit() {}

prependMedia(type: string) {
 console.log(type);
 this.mediaElements.push(this.element);
}

HTML File that would add the component once a new model for it has been added to the mediaElements array:

<div *ngFor="let element of mediaElements" [(ngModel)]="mediaElements">
  <div *ngIf="element.name == 'elementOne'">
    <app-elementone></app-elementone>
  </div>
</div>

My question: What is wrong about the method I use with the ngFor? Not in an opinionated way but technically. What is the "best practice" way of adding a component to the DOM when a user clicks a button to add it to the page? And why? Not in an opinionated way but technically or withe evidence from Angular team.

I originally was going to go with how I showed in code, but now I have found both the Angular way and the Angular Material way and I am looking for facts about the best way.

Please advise? As some people feel this is too open for opinions, keeping it technical will help.

Let me know if you need any further description.

Thank you, Eric


Solution

  • The *ngFor syntax you're using is the standard approach

    Dynamic components are more suited to situations where you don't know what components you might require. An example of this is a Modal Dialog, where the modal might have to display components of any type - or if you have a third party library that displays components passed in by the library user

    If you don't need the outter div, you could use:

    <ng-container *ngFor="let element of mediaElements">
    
    </ng-container>
    

    Where you have <div *ngIf="element.name == 'elementOne'">, you could use an *ngSwitch, where the switch case would be the element name - this would suit if there were a few different components you need to render. There's a good ngSwitch example on the Angular Docs site, that's pretty close to what you're doing (as far as I can tell)

    Note: I'm not sure why you need the ngModel binding. It's better practice to dispatch events from the template, and update bindings in the component