Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic components at specified index not placed properly

I am trying to show a simple list of items in Angular with a clickable div on the side; on user selection, the component should dynamically create a new component below the clicked one.

For this purpose, i am using ComponentFactoryResolver with no relevant problems; however, using ViewContainerRef as parent, i can't find how to place the created components at a specified index, even if i specify it as a parameter in the createComponent() method.

app.component.html

<h3>Click on the arrow to create a component below the item clicked.</h3>

<div #myContainer>
  <div *ngFor="let thing of things; let index = index">
    <div class="inline click" (click)="thingSelected(thing, index)"> > </div>
    <div class="inline">{{thing.id}}</div>
    <div class="inline">{{thing.name}}</div>
    <div class="inline">{{thing.value}}</div>
  </div>
</div>

app.component.ts

export class AppComponent  {  
  @ViewChild('myContainer', { read: ViewContainerRef }) container: ViewContainerRef;

  things = [];
  constructor(private componentFactoryResolver: ComponentFactoryResolver){
    for(let i=0; i < 10; i++)
      this.things.push({id: i, name: "thing" + i, value: 5 * i});    
  }

  thingSelected(thing: any, index: number){
    let component = this.container.createComponent(this.componentFactoryResolver.resolveComponentFactory(DetailComponent), index);
    component.instance.id = thing.id;    
  }
}

I also created a stackblitz sample to demostrate the issue: what i am missing or doing wrong?

To clarify:

  1. I would like to reproduce something similar to "RowExpand" functionality in TurboTable of PrimeNg library. The user clicks a row, and a dynamic component is created at the position clicked.
  2. I don't know the type of component at runtime: that's why i want a dynamic component creation (so, specifying it in the html template it's not what i need)
like image 785
illeb Avatar asked Jul 23 '18 10:07

illeb


1 Answers

Ok, here is working example with @ViewChildren

https://stackblitz.com/edit/angular-gxmj4s?file=src%2Fapp%2Fapp.component.ts

  @ViewChildren('details', { read: ViewContainerRef }) containers: QueryList<ViewContainerRef>;

  thingSelected(thing: any, index: number) {
    const containersArray = this.containers.toArray();
    let component = containersArray[index].createComponent(this.componentFactoryResolver.resolveComponentFactory(DetailComponent));
    component.instance.id = thing.id;
  }

And

<div #myContainer>
  <div *ngFor="let thing of things; let index = index">
    <div class="inline click" (click)="thingSelected(thing, index)"> > </div>
    <div class="inline">{{thing.id}}</div>
    <div class="inline">{{thing.name}}</div>
    <div class="inline">{{thing.value}}</div>
    <div #details></div>
  </div>
</div>

Results in

enter image description here

like image 184
Antoniossss Avatar answered Nov 05 '22 12:11

Antoniossss