2

Ciao,

I'm working with Angular 8 and I've a problem sorting "computed" columns. Assuming that I have a object with two properties name and description, the sorting not works if I try to concatenate the value with a function inside the .ts file.

This is my markup:

<div class="col-md-12">
    <div class="row">

        <div class="example-container mat-elevation-z8">
            <mat-table [dataSource]="dataSource" matSort>
                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
                <ng-container matColumnDef="name">
                    <mat-header-cell *matHeaderCellDef mat-sort-header> TOKEN NAME </mat-header-cell>
                    <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
                </ng-container>

                <ng-container matColumnDef="description">
                    <mat-header-cell *matHeaderCellDef mat-sort-header> INDUSTRY </mat-header-cell>
                    <mat-cell *matCellDef="let row" [style.color]=""> {{row.description}} </mat-cell>
                </ng-container>

        <ng-container matColumnDef="namedescription">
                    <mat-header-cell *matHeaderCellDef mat-sort-header> NameDescription </mat-header-cell>
                    <mat-cell *matCellDef="let row" [style.color]=""> {{concatena(row)}} </mat-cell>
                </ng-container>

            </mat-table>

            <mat-paginator #paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
        </div>
    </div>
</div>

This is my code:

import { Component, ViewChild, OnInit, ElementRef } from '@angular/core';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { Router } from '@angular/router';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular 5';

  displayedColumns = ['name', 'description', 'namedescription'];
  dataSource: MatTableDataSource<any> = new MatTableDataSource(this.loadTokens());
  id: any;
  // resultsLength = 0;
  // pageSize = 5;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor() { }

  ngOnInit() {
    this.loadTokens();
  }

  loadTokens() {
    return [
      {
        "name": "sss",
        "description": "It"
      },
      {
        "name": "aa",
        "description": "Hositality"
      },
      {
        "name": "bbb",
        "description": "Construction"
      },
      {
        "name": "ccc",
        "description": "sample data1"
      },
      {
        "name": "ddd",
        "description": "sample data2"
      },
      {
        "name": "eee",
        "description": "sample data3"
      },
    ];
  }

  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }

  applyFilter(filterValue: string) {
    filterValue = filterValue.trim(); // Remove whitespace
    filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
    this.dataSource.filter = filterValue;
  }

  concatena(row: any):any{
    return row.name + ' ' + row.description;
  }
}

I've reproduced the problem on stackbliz.

https://stackblitz.com/edit/mat-sort-p4ypos

How can I resolve this problem?

Thanks

ilMattion
  • 1,841
  • 2
  • 24
  • 47
  • 1
    MatSort sorts by the property defined in matColumnDef by default if you don't specify anything different. It looks up whether the property exists and sorts by it. The answers by Cookie and Bojan Kogoj is how you could solve it. – sombrerogalaxy May 22 '20 at 09:21

2 Answers2

4

You can handle the data sorting yourself to make this work:

  ngAfterViewInit() {
       this.dataSource.paginator = this.paginator;
       this.dataSource.sortingDataAccessor = (item, property) => {
        switch (property) {
            case 'namedescription':
                return item.name + ' ' + item.description;
            default:
                return item[property];
        }
    };
    this.dataSource.sort = this.sort;

}

Cookie
  • 136
  • 4
2

You could create dynamic data before sending it to MatTableDataSource, this way it will know what the value it will be.

Basically

dataSource: MatTableDataSource<any> = new MatTableDataSource(this.addRowDescription(this.loadTokens()));
  addRowDescription(data: any[]): any[] {
    return data.map((row: any) => ({
      ...row,
      namedescription: row.name + " " + row.description
    }));
  }

I added an example https://stackblitz.com/edit/mat-sort-owqwfk

Bojan Kogoj
  • 5,321
  • 3
  • 35
  • 57