0

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?

  • Does this answer your question? [Insert dynamically create component after clicked row](https://stackoverflow.com/questions/52535851/insert-dynamically-create-component-after-clicked-row) – l -_- l Jun 28 '22 at 10:20
  • No. It similar, but it's still not what I need. – waxono7326 Jun 28 '22 at 10:26
  • Please be clearer in your answers. How is it different from the expected behavior ? – l -_- l Jun 28 '22 at 10:27
  • The question there is about rows, and my question is about cells. And I think that adding ng-template to ALL cells is overkill. I hope there is some more elegant solution. – waxono7326 Jun 28 '22 at 10:39

1 Answers1

0

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>
l -_- l
  • 618
  • 4
  • 15
  • Thanks, that's a great solution! But ComponentFactoryResolver is depricated for Angular v13. Is it possible to implement something similar on modern version of Angular (v13-14)? – waxono7326 Jun 28 '22 at 11:02
  • Welcome :) I've updated my answer with a Factory-less version – l -_- l Jun 28 '22 at 12:29