ngx-datatable - custom columns with action buttons

22,296

Solution 1

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.

Solution 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+.

Solution 3

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

Share:
22,296
Codehan25
Author by

Codehan25

Updated on July 09, 2022

Comments

  • Codehan25
    Codehan25 almost 2 years

    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);
    }
    
  • Codehan25
    Codehan25 about 5 years
    I've updated my question with your approach. Now the buttons are no longer visible inside the columns..
  • wentjun
    wentjun about 5 years
    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.
  • Abhishek Soni
    Abhishek Soni about 4 years
    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.