CharybdeBE
CharybdeBE

Reputation: 1843

Use angular component for ngx-datatable column

I use ngx-datatable a lot in my app and I would like to have some generic template for the column and their respective header.

For now I have

<ngx-datatable #myTable
        XXX>
   <ngx-datatable-column
       name="selection">
       <ng-template let-column="column" ngx-datatable-header-template>
           <app-component-header-table></app-component-header-table>
       </ng-template>
       <ng-template let-row="row" ngx-datatable-cell-template>
           <app-component-content-table></app-component-header-table>
       </ng-template>
  </ngx-datatable-column>
.... rest of the table ...
</ngx-datatable>

What i would like to achieve is to have the component that contains the content and the one that contains the header in a single file/component

And use it more or less like that :

<ngx-datatable #myTable
        XXX>
   <ngx-datatable-column
       name="selection">
       <app-custom-column></app-custom-column>
  </ngx-datatable-column>
.... rest of the table ...
</ngx-datatable>

With obviously the possibility to access the objects column and row inside

Upvotes: 0

Views: 4371

Answers (1)

Roman Leliuk
Roman Leliuk

Reputation: 91

A lot of time wasted in searching better way to avoid copypast in ngx-datatable. There is my solution:

  1. Create new component-handler, i call them - "custom-table".
  2. Provide to this component rows and cols @inputs
  3. Listen changes cols and rewrite columns property.
  4. Declare ViewChild with your custom table cell.

custom-table.ts

export class CustomTableComponent implements OnInit, OnChanges {
  columns = [];

  @ViewChild('table', { static: false }) table: any;
  @ViewChild('primary', { static: true }) primary: TemplateRef<any>;
  @ViewChild('withAvatar', { static: true }) withAvatar: TemplateRef<any>;

  @Input() rows: Array<any>;
  @Input() cols: Array<Object>;

  public selected: TableColumnModelExtended[] = [];

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.hasOwnProperty('cols') && changes.cols.currentValue) {
      this.updateCols();
    }
  }

  ngOnInit() {
    if (this.cols) {
      this.updateCols();
    }
  }

  updateCols(): void {
    this.columns = this.cols.map((col: TableColumnModelExtended) => ({
      ...col,
      cellTemplate: this[col.cellTemplate],
      headerTemplate: this[col.headerTemplate],
    }));
  }
}

custom-table.html

<div class="custom-table">
  <ngx-datatable
    #table
    columnMode="force"
    [rows]="rows"
    [columns]="columns">
  </ngx-datatable>

  <!--COLUMN WITH AVATAR-->
  <ng-template #withAvatar let-value="value" let-row="row">
    <column-with-avatar [value]="value"></column-with-avatar>
  </ng-template>


  <!--PRIMARY COLUMN-->
  <ng-template #primary let-value="value" let-row="row" let-column="column">
    <column-primary [value]="value" [column]="column"></column-primary>
  </ng-template>

</div>

After that you can use it like this.

example-component.ts

export class ExampleComponent {
  public columns: TableColumnModel[] = ExampleListColumns;
  readonly valueList$: BehaviorSubject<DeliveryNote[]> = new BehaviorSubject([]);

}

example-component.html

<custom-table
  [rows]="valueList$ | async"
  [cols]="columns">
</custom-table>

example-component-table.config.ts

export const ExampleListColumns: TableColumnModelExtended[] = [
  {
    cellTemplate: 'primary',
    name: 'Quantity',
    prop: 'quantity',
    cellClass: 'right',
  },
  {
    cellTemplate: 'withAvatar',
    name: 'Avatar',
    prop: 'userAvatar',
  }
];

Be careful with defining column config. You should not to use extra ',' after end of array.

At the end, you get a table that uses the config to display components, and does not repeat the html code over and over.

To add a new column type, you just need to describe it once inside the component and create a @ViewChild inside the component.

Upvotes: 1

Related Questions