rjustin
rjustin

Reputation: 1439

Angular 4 using ngComponentOutlet to display dynamically changing ContentChildren

My ultimate goal is to just have a custom container component with a dynamic list of custom card components that are individually accessible (not as a single entity using ng-content).

<custom-card-holder> <custom-card></custom-card> <custom-card></custom-card> ... <custom-card></custom-card> </custom-card-holder>

Ideally I just grab the child components with ContentChildren query and put each one into a styled div inside the custom card holder.

The displaying each content child individually in the styled div to get it to fit nicely in the holder.

I have tried using TemplateOutlet and a few other odds and ends but the ComponentOutlet seems the most promising.

I would like to avoid any extra clutter on the code shown above. I understand the data can just be input and the component can be used inside without any transclusion but that just means a more complex interface for others to figure out.

Upvotes: 0

Views: 1559

Answers (1)

rjustin
rjustin

Reputation: 1439

@Arivinds comment here led to fixed a syntax problem and also a semi-workaround for the original issue.

  1. The ngComponentOutlet takes a Type/Class not an instance.

  2. Nesting the Class in a list with the instance:

    cardList = [{ component:CardClass,context:instance}]

In the end I added a CardHolder component which template is just a <ng-content></ng-content> and instead of Card class I had CardHolder in the cardList.

Then I used the content property of ngComponentOutlet to project my actual Card into the CardHolder.

 cardList:any[] = [
  {
    type:CardHolder,
    context:{}
  }
  ];

`<div #scrollItem class="item" *ngFor="let card of cardList">
  <ng-container *ngComponentOutlet="card.type;content: card.context;"></ng-
container>
</div>`

The catch is that content(ngComponentOutlet) takes a Node so When I query for ContentChildren I purposefully grabbed the ElementRef and used nativeElement. Note the double square brackets.

`ngAfterContentInit(){
    this.cardList = this.cards.toArray().map((card)=>{
       return {type:CardHolder,context:[[card.nativeElement]]};
    })
 }`

Hope this helps anyone in the same boat.

Note: The ability to add inputs to dynamic components is supposedly in the works/backlogged but currently not implemented

Note: Also I believe any dynamic components must be in the entryComponents array of the NgModule

Upvotes: 1

Related Questions