Angular Component To Control Table Columns

TL;DR? See this video:

One of our client demand a flexibility for users to define columns order and their visibility. This requirement was requested when we already had a lot of tables in the application. So we needed an easy way to apply the feature to all tables.

The component that we created is used to wrap a table tag with our custom tag: <p-table>. Well, it is not that simple actually. We need to define how the custom column order/visibility to be saved so we can load it next time user visit the same page and give user the exact same display when user leaved it.

See the demo below:

 

<p-table [tableInfo]="tableInfo">
   <table class="table table-stripped table-bordered ">
      ...
   </table>
</p-table>

In the typescript file, there is a declaration of tableInfo variable. There is also a routine to save and load the configuration. In this snippet code, the configuration is saved to browser’s localStorage.

constructor() {
  this.tableInfo = new TableInfo;
  this.tableInfo.key = 'table1';//key to make it unique in localStorage
  this.tableInfo.onSave = () => {
    //this routine is triggered when user change the order/visibility of the columns
    this.saveDefaultParameter(this.tableInfo.key, JSON.stringify(this.tableInfo.columnsInfo));
  };
  
  //load configuration
  let savedInfo = this.getDefaultParameter(this.tableInfo.key);
  let columnsInfo = JSON.parse(savedInfo);
  this.tableInfo.columnsInfo = columnsInfo;

  ...
}
  
saveDefaultParameter(paramName: string, value: string) {
  localStorage.setItem(paramName, value);
}

getDefaultParameter(paramName: string): string {
  return localStorage.getItem(paramName);
}

We can call a web service on the server if we want to save the configuration on server’s database.

Of course we don’t want that routine to be written everywhere. So we can create a default TableInfo implementation. For example:

import {TableInfo} from './CmpTable';

export class DefaultTableInfo extends TableInfo {
  key: string;
  constructor(key: string) {
    super();
    this.key = key + '_p-table';
    let saved = this.read();
    let columnsInfo = JSON.parse(saved);
    this.columnsInfo = columnsInfo;
    this.onSave = () => {this.save()};
  }
  
  save() {
    localStorage.setItem(this.key, JSON.stringify(this.columnsInfo));
  }

  read(): string {
    return localStorage.getItem(this.key);
  }
}

And then on the *.ts file using this component, we instantiate tableInfo object from DefaultTableInfo.

constructor() {
  this.tableInfo = new DefaultTableInfo(this.constructor.name);
  //above code send the class name as table info key. If this page contains more than one table
  //ensure to add the parameter with a unique string
}

One more thing, call this.tableInfo.relayoutBody(); when the data of the table is reloaded. It will trigger the component to adjust it self accordingly.