I have created a table component that generates a table based on a configuration I pass in. I'm aware there are likely better ways of writing a re-usable component, but for now this is what I have.
Basically the component takes a config with a columns and datasource object then it maps the columns to the properties in the datasource.
My problem is that at some point I make changes to one of the table's datasources, I first empty the array for instance...
this.members.datasource = []
then I push the new data onto the datasource like so...
for (let member in members) {
            this.members.datasource.push(members[member]);
}
My problem is that when I do this the table does not update with the new data in the datasource.
I have utilized the ngDoCheck function in my component and it does indeed trigger when I change the datasource, but nothing else happens.
Here is all relative code and markup...
ip-datatable component
import { Component, Input, Output, OnInit, EventEmitter, ElementRef, DoCheck } from "@angular/core";
import { ITable } from "./interfaces/index";
@Component({
    selector: "ip-datatable",
    templateUrl: "./ip-dataTable.component.html"
})
export class IpDataTableComponent implements OnInit, DoCheck {
    @Input()
    public config: ITable;
    public tableData: any;
    @Output()
    private onRowClick = new EventEmitter();
    constructor(private elem: ElementRef) {
    }
    public ngOnInit() {
        // TODO: Decide whether or not to make this more dynamic (ie: excepts functions returning things other than a promise)
        if (typeof (this.config.datasource) == "function") {
            this.config.datasource()
                .then((data: any) => {
                    this.tableData = data;
                });
        } else {
            this.tableData = this.config.datasource;
        }
    }
    public rowClicked(e:Event) {
        this.onRowClick.emit(e);
    }
    public ngDoCheck() {
    }
}
The ip-datatable component's template html
<table class="table table-bordered table-hover">
    <thead>
    <tr>
        <td *ngFor="let column of config.columns">{{column.header}}</td>
    </tr>
    </thead>
    <tbody>
    <tr 
        *ngFor="let item of tableData" 
        [class]="(config.rowConfig !== undefined) ? config.rowConfig.classes : ''" 
        (click)="rowClicked($event)" [id]="(item.id !== undefined) ? item.id : ''">
        <td *ngFor="let column of config.columns">{{item[column.mapKey]}}</td>
    </tr>
    </tbody>
</table>
Component that utilizes ip-datatable
import { Component, OnInit, AfterViewInit, ApplicationRef } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { EngagementService } from "../../services/engagement.service";
import { EngagementEditModel } from "../../models/index";
import { ITable } from "../../core/components/ip-datatable/interfaces/index";
@Component({
    templateUrl: "engagement-context.component.html"
})
export class EngagementContextComponent {
    public id: string;
    public engagementDetails: EngagementEditModel;
    // Temporarily hardcode groups as there is only two available.
    public groups: ITable = {
        columns: [
            {
                header: "Name",
                mapKey: "name"
            }
        ],
        rowConfig: {
            classes: "clickable override"
        },
        datasource: [
        {
            name: "Owners"
        },
        {
            name: "Users"
        }]
    };
    public members: ITable = {
        columns: [
            {
                header: "Name",
                mapKey: "name"
            }
        ],
        datasource: []
    }
    constructor(private engagementService: EngagementService, private route: ActivatedRoute, private appRef: ApplicationRef) {
        this.id = route.snapshot.params["id"];
            this.engagementService.getEngagementEditDetailsById(parseInt(this.id))
            .then((data: EngagementEditModel) => {
                this.engagementDetails = data;
                console.log(this.engagementDetails); // tslint:disable-line
            });
    }
    public groupClicked(e: Event) {
        // Get the element of the event
        let elem: IEventElement = e.currentTarget;
        // Get the name of the selected node
        let groupName = elem.textContent.trim().toLowerCase();
        let members = (<any>this.engagementDetails)[groupName];
        interface IEventElement extends EventTarget {
            textContent?: string;
        }
        this.members.datasource = [];
        for (let member in members) {
            this.members.datasource.push(members[member]);
        }
    }
}
HTML usage of the ip-datatable
<div class="row">
        <div class="col-md-12">
            <section class="section">
                <div class="section-body">
                    <h4 class="section-title">Groups</h4>
                    <ip-datatable
                        [config]="groups"
                        (onRowClick)="groupClicked($event)">
                    </ip-datatable>
                </div>
            </section>
        </div>
        <div class="col-md-12">
            <section class="section">
                <div class="section-body">
                    <h4 class="section-title">Members</h4>
                    <ip-datatable
                        [config]="members"
                    ></ip-datatable>
                </div>
            </section>
        </div>
    </div>