Back in AngularJS, I created a simple smart table component that could be used like this for our team:
<smart-table items="vm.people">
    <column field="name">{{row.firstname}} {{row.lastname}}</column>
    <column field="age">{{vm.getAge(row.birthday)}}</column>
</smart-table>
This is a contrived example, but it worked like this. it generated the table, with the headers and used the inner content of the <column> tag as the template for each cell (the <td> element) correctly.
Now, I am trying to port this to Angular (6+). So far, using @ContentChildren I am able to easily extract the list of columns.
import { Component, OnInit, Input, ContentChildren, QueryList } from '@angular/core';
@Component({
    selector: 'app-root',
    template: `
<app-table [data]="data">
    <app-column title="name">{{name}}</app-column>
    <app-column title="age">{{birthday}}</app-column>
</app-table>
`,
})
export class AppComponent {
    data = [{
        name: 'Lorem Ipsum',
        birthday: new Date(1980, 1, 23),
    }, {
        name: 'John Smith',
        birthday: new Date(1990, 4, 5),
    }, {
        name: 'Jane Doe',
        birthday: new Date(2000, 6, 7),
    }];
}
@Component({
    selector: 'app-column',
    template: ``,
})
export class ColumnComponent implements OnInit {
    @Input() title: string;
    constructor() { }
    ngOnInit() {
    }
}
@Component({
    selector: 'app-table',
    template: `
<table>
    <thead>
    <th *ngFor="let column of columns">{{column.title}}</th>
    </thead>
    <tbody>
    <tr *ngFor="let row of data">
        <td *ngFor="let column of columns">
        <!-- <ng-container *ngTemplateOutlet="column.title;context:row" ></ng-container> -->
        </td>
    </tr>
    </tbody>
</table>
`,
})
export class TableComponent implements OnInit {
    @Input() data: any[];
    @ContentChildren(ColumnComponent) columns: QueryList<ColumnComponent>;
    constructor() { }
    ngOnInit() {
    }
}
This renders the following HTML:
<table>
    <thead>
        <!--bindings={"ng-reflect-ng-for-of": "[object Object],[object Object"}-->
        <th>name</th>
        <th>age</th>
    </thead>
    <tbody>
        <!--bindings={"ng-reflect-ng-for-of": "[object Object],[object Object"}-->
        <tr>
            <!--bindings={"ng-reflect-ng-for-of": "[object Object],[object Object"}-->
            <td></td>
            <td></td>
        </tr>
        <tr>
            <!--bindings={"ng-reflect-ng-for-of": "[object Object],[object Object"}-->
            <td></td>
            <td></td>
        </tr>
        <tr>
            <!--bindings={"ng-reflect-ng-for-of": "[object Object],[object Object"}-->
            <td></td>
            <td></td>
        </tr>
    </tbody>
</table>
But now I am stuck trying to insert the content of the <app-column> component into the <app-table> template. I have read several answers around here (this one and this one). But the issue I have with those is that either you have a static set of templates or you insert them in static places.
In my case, I need to use that template inside an *ngFor at runtime.
In AngularJS, I was using the following code:
function compile(tElement) {
    const columnElements = tElement.find('column');
    const columns = columnElements.toArray()
        .map(cEl => ({
            field: cEl.attributes.field.value,
            header: cEl.attributes.header.value,
        }));
    const template = angular.element(require('./smart-table.directive.html'));
    tElement.append(template);
    // The core of the functionality here is that we generate <td> elements and set their
    // content to the exact content of the "smart column" element.
    // during the linking phase, we actually compile the whole template causing those <td> elements
    // to be compiled within the scope of the ng-repeat.
    const tr = template.find('tr[ng-repeat-start]');
    columnElements.toArray()
        .forEach(cEl => {
            const td = angular.element('<td/>')
                .html(cEl.innerHTML);
            tr.append(td);
        });
    const compile = $compile(template);
    // comment out originals
    columnElements.wrap(function () {
        return `<!-- ${this.outerHTML} -->`;
    });
    return function smartTableLink($scope) {
        $scope.vm.columns = columns;
        compile($scope);
    };
}
 
    