4

I am having trouble getting my angular-datatable to show a new column list after a rerender. I have followed the example shown in the docs for rerendering and I can get the table to rerender. I am able to manipulate certain features like searching and pageLength, but for some reason I cannot get my columns to change.

I have a very deep data set that would make my table look awful if I rendered all the columns at once, so I would like to give users the ability to select which columns they see.

I would even be open to loading in all the columns at once and just switching visibility off and on, but I cannot effect visibility either.

Has anyone had this issue before?

Rerender function:

rerender(): void {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
  dtInstance.destroy();
  // these work
  this.dtOptions.searching = true;
  this.dtOptions.pageLength = 2;
  // these do not
  this.dtOptions.columns = newColumnList;
  this.dtOptions.columns[some-index].visible = false;
  this.dtTrigger.next();
});}

Initial dtOptions:

this.dtOptions = {
  searching: false,
  pagingType: 'full_numbers',
  pageLength: 10,
  retrieve: true,
  serverSide: true,
  processing: true,
  language: {
    zeroRecords: 'Nothing Found'
  },
  ajax: (dataTablesParameters: any, callback) => {
    const payload = this.passFilterService.processPagination(this.filter, dataTablesParameters);
    this.http
      .post<any>(
        environment.api + '/things/list',
        {payload: payload}, {}
      ).subscribe(resp => {
        if (resp.data.data === null) {
          resp.data.data = 0;
        }
      callback({
        recordsFiltered: resp.data.totalCount,
        data: resp.data.data,
        recordsTotal: resp.data.totalCount
      });
    });
  },
  columns: this.tableColumns
};

Initial Columns (limited fields):

tableColumns = [
{
  title: 'Customer',
  data: 'Id',
  render: function(data) {
    return `<a href="/pass/` + data + `" class="cursor-pointer actionView" title="View">Action</a>`;
  }
}, {
  title: 'Created',
  data: 'createdAt',
  orderable: true,
  visible: true,
}, {
  title: 'Updated',
  data: 'updatedAt',
  orderable: true,
  visible: true,
}, {
  title: 'Disabled',
  data: 'isVoided',
  orderable: true,
  visible: true,
}
];

Table implementation:

<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="row-border hover">
</table>
J.Langford
  • 225
  • 3
  • 11

1 Answers1

1

I faced the same issue, spent hours debugging it until I found something that worked for me. I will advice separating the DT config into an independent object that can be loaded separately. Once you update your DT options and any other config, you can use the functions below to reload the entire DT, destroying and reloading it accordingly;

async rerender(newSettings?: DataTables.Settings) {
    try {
        this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
            if (newSettings) {
                // FIX To ensure that the DT doesn't break when we don't get columns
                if (newSettings.columns && newSettings.columns.length > 1) {
                    dtInstance.destroy();
                    this.dtOptions = Promise.resolve(newSettings);
                    this.displayTable(this.dtTableElement);
                }
            }
        });
    } catch (error) {
        console.log(`DT Rerender Exception: ${error}`);
    }
    return Promise.resolve(null);
}

This function calls the below one to actually destroy the DT and rerender it.

private displayTable(renderIn: ElementRef): void {
    this.dtElement.dtInstance = new Promise((resolve, reject) => {
        Promise.resolve(this.dtOptions).then(dtOptions => {
            // Using setTimeout as a "hack" to be "part" of NgZone
            setTimeout(() => {
                $(renderIn.nativeElement).empty();
                var dt = $(renderIn.nativeElement).DataTable(dtOptions);
                // this.dtTrigger.next();
                resolve(dt);
            });
        }).catch(error => reject(error));
    });
}

I removed the dtTrigger execution from the reconstruction function as this was executing twice.

The dtTableElement is defined as @ViewChild('dtTableElement') dtTableElement: ElementRef; where the HTML contains the respective reference on the datatable as:

<table #dtTableElement datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table table-striped row-border hover" width="100%"></table>