11

In my Angular app (using Angular Material) I have several tables.

The strange thing is that, in one case, sorting works, while, in another case, it doesn't.

Here is the table that works:

<table mat-table [dataSource]="dataSource" matSort>

  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef> ID </th>
    <td mat-cell *matCellDef="let row"> {{row.id}} </td>
  </ng-container>

  <ng-container matColumnDef="firstName">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> First Name </th>
    <td mat-cell *matCellDef="let row"> {{row.firstName}} </td>
  </ng-container>

  <ng-container matColumnDef="lastName">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Last Name </th>
    <td mat-cell *matCellDef="let row"> {{row.lastName}} </td>
  </ng-container>

  <ng-container matColumnDef="viewProfile">
    <th mat-header-cell *matHeaderCellDef class="viewProfile"> Profile </th>
    <td mat-cell *matCellDef="let row" class="viewProfile">
      <button mat-icon-button (click)="openProfile(row.id)">
                <mat-icon aria-label="icon-button with a page-view icon">pageview</mat-icon>
              </button>
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

</table>

... and here is the table that doesn't work:

<table class="table2" mat-table [dataSource]="dataSource2" matSort>

  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Project </th>
    <td mat-cell *matCellDef="let row"> {{row.name}} </td>
  </ng-container>
  <ng-container matColumnDef="role">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Role </th>
    <td mat-cell *matCellDef="let row"> {{row.role}} </td>
  </ng-container>
  <ng-container matColumnDef="beginning">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Beginning </th>
    <td mat-cell *matCellDef="let row"> {{row.beginning | date : "mediumDate"}} </td>
  </ng-container>
  <ng-container matColumnDef="end">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> End </th>
    <td mat-cell *matCellDef="let row"> {{row.end | date : "mediumDate"}} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns2"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns2;"></tr>
</table>

As you can see, in both cases I use "matSort" (in the table tag) and "mat-sort-header" (for the columns that are supposed to be sortable).

Furthermore, in each case I do the same import in the component.ts file:

import { MatTableDataSource, MatPaginator, MatSort, MatDialog } from '@angular/material';

I just don't get why sorting works in the first case but not in the second. Does anybody have any ideas what's going on here?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Tommy
  • 699
  • 4
  • 11
  • 26

5 Answers5

31

Make sure that the column_name in the displayedColumns array,

displayedColumns = ['column_name'];

the html container,

ng-container matColumnDef="column_name"

and the keys of the dataSource objects,

dataSource = [ {"column_name": "value"} ];

ALL MATCH PERFECTLY.

This can also be the reason that a specific set of data doesn't work and others do.

Naser AlOqab
  • 499
  • 4
  • 9
17

Are you sure your second table ( the one where sort is not working ) is not wrapped in a div with *ngIf ? Because that is a common problem, as when the template is rendered, because of the *ngIf, matSort is undefined. Here is how to fix it : Angular 5 Material Data Table sorting not working

wFitz
  • 1,266
  • 8
  • 13
  • Thank you for your suggested answer ... the table is wrapped inside several divs but none of these divs is with *ngIf – Tommy Aug 22 '18 at 15:07
  • thank you for your suggested answer <3 I used ngIf in mat-table tags. I removed it after sorting works :) – Nisanur Aug 13 '20 at 08:37
1

For data loaded using an API call:

It's possible that the sort was set before the data was loaded onto the table; thereby messing up sorting feature.


In that case, change:

** code to insert data into the table **

this.dataSource2.sort = this.sort;

To

** code to insert data into the table **

setTimeout(() => this.dataSource2.sort = this.sort, 2000); // Delay it by 2 seconds.

Where this.sort is:

@ViewChild(MatSort, { static: false }) sort: MatSort;
Ashil John
  • 7,362
  • 4
  • 19
  • 34
0

There is also another possible issue. Besides that column names have to match the attribute 'matHeaderRowDef' in 'mat-header-row *matHeaderRowDef', the column name also has to match the class field/property name of the content type used in the dataSource attribute.

e.g.

<mat-table [dataSource]="mySource" matSort>
        <!-- modelViewFieldNameOne has to match the class field/property name! -->
        <ng-container matColumnDef="modelViewFieldNameOne">
            <mat-header-cell  *matHeaderCellDef
                             mat-sort-header>just a column</mat-header-cell>
            <mat-cell *matCellDef="let tableItem">{{ tableItem.getterForMyField }}</mat-cell>
        </ng-container>


// typescript where 'mySource' is kept
mySource = new MatTableDataSource<MyModelViewType>();


// typescript of MyModelViewType
export class MyModelViewType{

   // this is important, it has to match the ng-container matColumnDef attribute!!!
   private modelViewFieldNameOne

   // this getter naming is not important for mat-table attributes
   public get getterForMyField(): string { 
     return this.modelViewFieldNameOne;
   }
}

My mat-table was sorting fine, until the model view type (i.e. MyModelViewType in the example above) was re-factored but only the field / property name changed, the getter() name was kept, the corresponding table column stopped sorting properly. Once the attribute matched the name it worked again.

I am using: @angluar/cdk 9.2.2

xordonkey
  • 89
  • 4
-1

I know my sort doesn't work when it thinks I mixed in data types. So on the list below it will stop sorting the Value column when it gets to the 587.
enter image description here

JBrooks
  • 9,901
  • 2
  • 28
  • 32