ngx-datatable - custom columns with action buttons

Codehan25 picture Codehan25 · Jun 14, 2019 · Viewed 15.7k times · Source

I have a table (ngx-datatable) in which I want to define an "actions" column in which buttons will then be placed for CRUD operations.

Creating the column and placing the buttons worked, but I have the problem that the selected row and the values ​​in its columns are no longer recognized inside my triggered function.

Here is my template:

<div class="col-12">
  <ngx-datatable
    #table
    class="material"
    [rowHeight]="'auto'"
    [columns]="columns"
    [columnMode]="'force'"
    [headerHeight]="50"
    [footerHeight]="50"
    [limit]="10"
    [rows]="cars?.content"
    [selected]="selected"
    [selectionType]="'multi'">
  </ngx-datatable>
</div>

Here is my custom template with the buttons:

<ng-template #buttonsTemplate let-row="row" let-value="value" let-button="column.actions">
  <button class="btn btn-transparent" (click)='onSelect($event)'><i class="rb-ic rb-ic-add-frame"></i></button>
  <button class="btn bt n-transparent" (click)='onSelect($event)><i class="rb-ic rb-ic-abort-frame"></i></button>
  <button class="btn btn-transparent" (click)='onSelect($event)><i class="rb-ic rb-ic-reset"></i></button>
  <button class="btn btn-transparent" (click)='onSelect($event)><i class="rb-ic rb-ic-agility"></i></button>
</ng-template>

My component (.ts file) is structured like this:

export class MyComponent implements OnInit, OnDestroy {
  @ViewChild('buttonsTemplate') buttonsTemplate: TemplateRef<any>;
  columns = [];

  ngOnInit() {
    this.columns = [
    {prop: 'id', name: 'Id'},
    {prop: 'serial_number', name: 'Serial Number'},
    {prop: 'actions', name: 'Actions', cellTemplate: this.buttonsTemplate}
    ];
  }

  // This method should be called after clicking an action button
  onSelect({selected}) {
    console.log('Array of selected vehicles', selected);
  }
}

Currently this error occurs in the console:

ERROR TypeError: Cannot read property 'serial_number' of undefined

What am I doing wrong? The official documentation and demo page doesn't helped me..


Approach from @wentjun (not working: button not visibile inside column)

The Template:

<ngx-datatable-column *ngFor="let column of columns; let i = index;" name="{{column.name}}" prop="{{column.prop}}">
  <ng-template #buttonsTemplate let-row="row" let-value="value" ngx-datatable-cell-template>
    <button class="btn btn-transparent" (click)='onSelect(row)'><i class="rb-ic rb-ic-add-frame"></i></button>
  </ng-template>
</ngx-datatable-column>

The Component (function):

onSelect({selected}) {
  console.log('Array of selected vehicles', selected);
}

Answer

wentjun picture wentjun · Jun 14, 2019

I am using the ngx-datatable library, and I have a similar setup to your project, thus I believe I see where your problem is coming from.

If your <ng-template> is not nested within the <ngx-datatable-column>,you should put it within it. In addition, on your click event binding, you should be passing the row values into your onSelect() methods, since you are trying to access the row data. You will need to use the ngx-datatable-cell-template directive within your <ng-template> too.

This are the changes you should be making:

<ngx-datatable 
[rows]="rows" 
class="material" 
[loadingIndicator]="loadingIndicator"
[columnMode]="'force'" 
[headerHeight]="50" 
[footerHeight]="50" 
[rowHeight]="'auto'"
[columns]="columns" 
[reorderable]="reorderable">

  <ngx-datatable-column *ngFor="let column of columns; let i = index;" name="{{column.name}}" prop="{{column.prop}}">
    <ng-template let-value="value" let-row="row" *ngIf="column.name==='Actions'" ngx-datatable-cell-template>
      <span>
        <button style="background-color:red;height:15px;" (click)='onSelectRed(row)'><i class="rb-ic rb-ic-add-frame"></i></button>
        <button style="background-color:blue;height:15px;" class="btn" (click)='onSelectBlue(value)'><i class="rb-ic rb-ic-add-frame"></i></button>
      </span>
    </ng-template>
  </ngx-datatable-column>
</ngx-datatable>

And on your component.ts, you should be able to access the data of the entire row, or the value of the property itself, depending on the value you have binded on the click method.

onSelectRed(row) {
  console.log(row);
}

onSelectBlue(value) {
  console.log(value);
}

I have created a demo over here. As you can see, the values of row and the binded property (id) can be accessed within the row buttons itself.