9

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);
}
3
  • can you please post the response json (cars content) you are trying to populate
    – Vikash B
    Commented Jun 14, 2019 at 5:38
  • You mean --> {id: "5cfa46bc934b930018e66c", serial_number: "Tx2dh2"}
    – Codehan25
    Commented Jun 14, 2019 at 5:41
  • and It's structured like this --> content: (9) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
    – Codehan25
    Commented Jun 14, 2019 at 5:43

4 Answers 4

8

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.

3
  • I've updated my question with your approach. Now the buttons are no longer visible inside the columns..
    – Codehan25
    Commented Jun 14, 2019 at 12:52
  • Hi, I must apologise, for I wasn't very clear with my explanation. I have created a demo, and added more details in the code on my answer. Hope it clears things up for you.
    – wentjun
    Commented Jun 14, 2019 at 14:00
  • I have copied your code exactly line by line, I thought it may be some mistakes, but not worked for me. I don't know how, exact same is working when I modify your slackblitz code. Please point me to some link, I am not able to perform crud operation in my application. Commented Jun 2, 2020 at 3:40
2
<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+.

1

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

0

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

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.