13

I have this array:

this.dashboard = [
     {name: '<app-incassi-provvigioni></app-incassi-provvigioni>'},
     {name: '<app-scheda-punti-vendita></app-scheda-punti-vendita>'}
]

I populate this array on the ngOnInit cycle. I was wondering how can I render the components when I read my array in the html like that:

<gridster [options]="gridsterOptions">
    <gridster-item [item]="item" *ngFor="let item of dashboard">
        <!-- your content here -->
        {{item.name}}
    </gridster-item>
</gridster>

Of course right now it returns the string contained in the object but I'm trying to find a solution to render the component. It is possible to do that?

More details: I am developing a dashboard type app where I retrieve the list of the user dashlet from the DB and I'm trying to render those components dynamically once the main app component is ready. using Angular 7 & Gridster2.

Luca Alberto
  • 1,195
  • 3
  • 11
  • 30

5 Answers5

7

rather passing component tag name("app-incassi-provvigioni" in your case), pass the component name (TestComponenet), then call the function from your view and render it as dynamically with Directive.

eg:

<gridster [options]="gridsterOptions">
  <gridster-item [item]="item" *ngFor="let item of dashboard">
    <div class="inner">
      <ng-template dynamic-template> </ng-template>
    </div>
  </gridster-item>
</gridster>

dynamic-template is a directive, that help us to load the component.

Rap
  • 6,851
  • 3
  • 50
  • 88
indsoft
  • 83
  • 7
  • this sounds interesting, can you provide some code example please? – Luca Alberto Mar 28 '19 at 08:45
  • 4
    @LucaAlberto, i just did the sample code check the link: [link ] (https://stackblitz.com/edit/angular-yz8w1u). please mark as answer if this is suite for you. thanks – indsoft Mar 28 '19 at 10:06
  • 1
    Man, you just saved my day. This answer should be the accepted answer. – Mehroz Sep 24 '21 at 11:39
7

You can inject component dynamically

Just create component with @Input() component;

export class DynamicContentComponent implements OnInit {

  @Input() component: any;
  @Input() data: any;

  constructor(public viewContainerRef: ViewContainerRef,
              private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);
    this.viewContainerRef.clear();

    const componentRef = this.viewContainerRef.createComponent(componentFactory);
    (<DynamicComponentRef>componentRef.instance).data = this.data;
  }
}

And use it in HTML

<app-dynamic-content [component]="someComponent" [data]="data"></app-dynamic-content>

Data example

someComponent = SchedaPuntiVendita;

Dynamic components should be added to entryComponents in your module

Also you can create some kind of factory which will receive some string and depends on it returns you component class

Factory example

@Injectable()
export class DynamicContentComponentFactory {

  constructor() { }

  get(type: ContentType): any {
    switch (type) {
      case 'scheda':
        return SchedaPuntiVendita;
    }
  }

And modify DynamicContentComponent a little

@Input() contentType: string;

constructor(..., private factory: DynamicContentComponentFactory) { }
...

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.factory.get(this.contentType));

...
NechiK
  • 341
  • 2
  • 11
  • 2
    The ComponentFactoryResolver is no longer needed. The Angular team has streamlined it so you can directly create the component like this: `this.viewContainerRef.createComponent(this.component);` – Rap Dec 27 '21 at 18:51
2

Maybe you can use an angular switch for this:

<div [ngSwitch]="item.name">
    <app-incassi-provvigioni *ngSwitchCase="incassi"></app-incassi-provvigioni>
    <app-scheda-punti-vendita *ngSwitchCase="scheda"></app-scheda-punti-vendita>
</div>
Igor Benić
  • 53
  • 1
  • 7
0

if you are using gridster2, actually there is reference so you could use npm package as https://www.npmjs.com/package/ng-dynamic-component .

Here is an example of my code:

 <gridster-item
      class="gridster-item"
      [item]="item.gridItem"
      *ngFor="let item of dashboard; let i = index"
      (itemResize)="getItemSize($event, i)"
    >
      <button class="button-remove-item" (click)="removeItem(item)">
        <img src="assets/remove-item.svg" />
      </button>
      <div class="gridster-item-inner">
        <ndc-dynamic
          [ndcDynamicInputs]="item.size"
          [ndcDynamicComponent]="item.component.data"
        ></ndc-dynamic>
      </div>
    </gridster-item>

Let me know if you have any issues.

-1
this.dashboard = [
         {name: 'dashboard1'},
         {name: 'dashboard2'}
    ]

    <gridster [options]="gridsterOptions">
        <gridster-item [item]="item" *ngFor="let item of dashboard">
            <ng-container *ngIf="item.name === 'dashboard1'" *ngTemplateOutlet="dashboard1">
            </ng-container>
            <ng-container *ngIf="item.name === 'dashboard1'" *ngTemplateOutlet="dashboard2">
            </ng-container>
        </gridster-item>
    </gridster>


    <ng-template #dashboard1>
        <app-incassi-provvigioni></app-incassi-provvigioni>
    </ng-template>
    <ng-template #dashboard2>
        <app-scheda-punti-vendita></app-scheda-punti-vendita>
    </ng-template>
Syam Prasad
  • 149
  • 1
  • 1
  • 6