Search code examples
angularangular13angular14

How dynamic create component inside clicked table cell


some.component.html

<table>
  <tr *ngfor="let row in table">
    <td *ngFor="let cell in row" (click)="onCellClick($event)">Cell Text</td>
  </tr>
</table>
@Component({
  selector: 'app-my-component',
  template: '<div>My Component</div>',
})
export class MyComponent { }


@Component({
  selector: 'app-some',
  templateUrl: './some.component.html'
})
export class SomeComponent {
  public table = [[1, 2, 3], [4, 5, 6]];

  constructor(
    private viewContainerRef: ViewContainerRef
  ) { }

  onCellClick(event: MouseEvent): void {
    const myComponent = this.viewContainerRef.createComponent(MyComponent);
  }
}

This code adds MyComponent after </table>. But I need MyComponent to be created inside of the clicked table cell (inside td). How can I do it?


Solution

  • Note: This factory-less version only works if you have the same number of cells in every row (since we're using cellsPerRow to guess the index of the cell) :

    Alright, first import everything we'll need :

    import {
           Component,
           OnInit,
           ViewContainerRef,
           QueryList,
           ViewChildren,
    } from '@angular/core';
    

    Add a ViewChildren decorator below your constructor to get all the cells elems :

    @ViewChildren('cellElem', { read: ViewContainerRef })cellsElemsList: QueryList<ViewContainerRef>;
    

    Add a cellsPerRow constant :

    private cellPerRow = 3;
    

    Then modify your onCellClick like so :

    onCellClick = (rowIdx, colIdx) => {
        const cellIdx = (rowIdx * this.cellPerRow) + colIdx;
        this.cellsElemsList
          .filter((el, idx) => idx === cellIdx)[0]
          .createComponent(TestComponent);
      };
    

    Finally, change the HTML to pass the current cell's index to onCellClick() (and add the future component's container, #cellElem, inside your td elem) :

    <div *ngFor="let row of rows; let rowIdx = index;">
        <td *ngFor="let cell of row; let colIdx = index" (click)="onCellClick(rowIdx, colIdx)">
            <div #cellElem></div>
            Click me
        </td>
    </div>