5
votes

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);
}
4
can you please post the response json (cars content) you are trying to populateVikash B
You mean --> {id: "5cfa46bc934b930018e66c", serial_number: "Tx2dh2"}Codehan25
and It's structured like this --> content: (9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]Codehan25

4 Answers

3
votes

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.

1
votes

Credits to @m4limo

(I added my own observations)


Original comment

just use the ng-tamplate:

<ngx-datatable-column name="Actions" sortable="false" prop="id">
      <ng-template let-row="row" let-value="value" ngx-datatable-cell-template>

            <button md-icon-button (click)="blockAgents(value)">
              <i class="fa fa-ban"></i>
            </button>

            <button md-icon-button (click)="approveAgent(value)">
              <i class="fa fa-check"></i>
            </button>

      </ng-template>
</ngx-datatable-column>

value corresponds to the property prop you define in ngx-datatable-column, in this case id


Observations

You need to declare the column prop name inside the prop property of the ngx-datatable-column element, let-value will assign the property to a variable, in this case, named "value", which will be assigned/used in your ng-template child object.

"value" will get the property value from your row (object listed) using the column prop value. The column prop name NEED to match with a property of the row object.

Notes

  • Tested in Angular 9.1.1 (using Ivy)
  • Using @swimlane/ngx-datatable 16.0.3

Original GitHub comment here

1
votes
<ng-container *ngFor='let column of columns' >
            <ngx-datatable-column *ngIf='column.name === "Actions"' name="Actions" prop="actions">
                <ng-template let-value="value" let-row="row" ngx-datatable-cell-template>
                    <span>
                        <button class='btn btn-icon icon-left'>
                            Continue
                            <i [ngClass]='row.actions.continue'></i>
                        </button>
                        <button class='btn btn-icon icon-left'>
                            Remove
                            <i [ngClass]='row.actions.delete'></i>
                        </button>
                    </span>
                </ng-template>
            </ngx-datatable-column>
            <ngx-datatable-column *ngIf='column.name !== "Actions"' name="{{column.name}}" prop="{{column.prop}}">
            </ngx-datatable-column>
        </ng-container>

OP wentjun's solution works better with an ng-container in Angular 10+.

0
votes

Pass row instead of $event on click.

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

and in the onSelect function, you will be able to access the row details.

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

Please find the working demo