Default sorting in Angular Material - Sort header

AngularAngular Material

Angular Problem Overview


How can I change Angular Material code below, so that data-table is sorted by 'name' column, ascending order by default. Arrow (indicating current sort direction) must be displayed.

This is what I want to achieve:

enter image description here

Original code:

<table matSort (matSortChange)="sortData($event)">
  <tr>
    <th mat-sort-header="name">Dessert (100g)</th>
    <th mat-sort-header="calories">Calories</th>
    <th mat-sort-header="fat">Fat (g)</th>
    <th mat-sort-header="carbs">Carbs (g)</th>
    <th mat-sort-header="protein">Protein (g)</th>
  </tr>

  <tr *ngFor="let dessert of sortedData">
    <td>{{dessert.name}}</td>
    <td>{{dessert.calories}}</td>
    <td>{{dessert.fat}}</td>
    <td>{{dessert.carbs}}</td>
    <td>{{dessert.protein}}</td>
  </tr>
</table>

I was trying something like this, but it doesn't work (no arrow displayed, not sorted)

<table matSort (matSortChange)="sortData($event)" matSortActive="name" matSortStart="asc" matSortDisableClear>

Here's link to Plunker

Angular Solutions


Solution 1 - Angular

You're mistaking matSortStart for matSortDirection.

Try this:

<table matSort (matSortChange)="sortData($event)" matSortActive="name" matSortDirection="asc" matSortDisableClear>

https://stackblitz.com/edit/angular-defaultsort?file=src/app/sort-overview-example.html

matSortStart can be used to reverse the cycle used when sort (e.g. when the user clicks to sort, it starts at desc instead of asc).

Edit: Thanks Ben for providing an updated example

Solution 2 - Angular

You can programmatically sort the table by invoking the sort(Sortable) method of the data source. Assuming you've got a dataSource component property for the data source:

// to put next to the class fields of the component
@ViewChild(MatSort) sort: MatSort
    
// to put where you want the sort to be programmatically triggered, for example inside ngOnInit
this.sort.sort(({ id: 'name', start: 'asc'}) as MatSortable);
this.dataSource.sort = this.sort;

Solution 3 - Angular

@ViewChild(MatSort) sort: MatSort;

this.dataSource.sort = this.sort;

const sortState: Sort = {active: 'name', direction: 'desc'};
this.sort.active = sortState.active;
this.sort.direction = sortState.direction;
this.sort.sortChange.emit(sortState);

should work. demo

And to show sorting direction arrow, add next css (workaround)

th.mat-header-cell .mat-sort-header-container.mat-sort-header-sorted .mat-sort-header-arrow {
    opacity: 1 !important;
    transform: translateY(0) !important;
}

Solution 4 - Angular

Update for Material (tested with v7.3):

@ViewChild(MatSort) matSort: MatSort;

private someMethod(): void {
  this.matSort.sort({ id: 'columnName', start: 'asc', disableClear: false });
}

This will also update the mat-sort-header's arrow without any workaround

Solution 5 - Angular

You can bind mat-table sort properties to you component variable also.

As @Andrew Seguin says:

<table matSort matSortActive="name" matSortDirection="asc">

This is proper way to set default sorting if you know which one is that.

In case that you get sorting from somewhere else (in my case from query string params), you can also do it like this (sorting arrows works perfectly here):

sortDirection: 'name',  // this can be changed or filled in any time
sortProperty: 'asc',


<mat-table matSort [matSortActive]="sortProperty" [matSortDirection]="sortDirection">

Solution 6 - Angular

There are several contributing factors that affect the behaviour. Mostly it's use of MatTableDataSource vs a hand-crafted derivative of DataSource. So different solutions may work in some cases and don't in others.

Anyway, it's an old bug that's been well covered on GitHub. Please upvote that GitHub issue to attract attention of the Angular team.

The most durable solution published on that GitHub thread (link) is to call the following method on applying a sorting order:

public setSort(id: string, start?: 'asc' | 'desc') {
    start = start || 'asc';
    const matSort = this.dataSource.sort;
    const toState = 'active';
    const disableClear = false;

    //reset state so that start is the first sort direction that you will see
    matSort.sort({ id: null, start, disableClear });
    matSort.sort({ id, start, disableClear });

    //ugly hack
    (matSort.sortables.get(id) as MatSortHeader)._setAnimationTransitionState({ toState });
}

Solution 7 - Angular

In my case sorting was not working because matColumDef id and mat-cell var is different

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

after making changes matColumnDef="firstName" to matColumnDef="name" which is same as item.name

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

it works fine for me

Solution 8 - Angular

Maybe have you tried to call on the init of the page the sort function forced on name and direction?

     ngOnInit() {
    let defSort: Sort = {};
    defSort.direction = 'asc';
    defSort.active = 'name';
    this.sortData(defSort);
  }

Solution 9 - Angular

I had to make default sort on load

const matSort = { id: defaultSort.name } as MatSortable;
this.sort.direction = defaultSort.sort === 'asc' ? '' : defaultSort.sort === 'desc' ? 'asc' : 'desc' as SortDirection;
this.sort.sort(matSort);

Solution 10 - Angular

The answer from @Andrew Seguin (first and accepted answer) did the visual trick for me, but it didn't sort the table.

My solution is to use the html code provided by @Andrew Seguin and call the sortData(sort: Sort) method myself, but how to do that? As specified in the documentation, the ,,Sort'' is an interface which hast two properties, active and direction and the interface must look something like that:

export interface Sort {
   active:string //The id/name of the column being sorted
   direction:string //asc or dsc depending on the use case (The sort direction)
}

So the trick is to call the sortData(sort: Sort) method in ngOnInit as follows:

ngOnInit(){
    //Do some nitialization
    this.sortData({active:'name', direction:'asc'});
}

sortData(sort: Sort) {
    //Your sorting algorithm (see examples in documentation, link above and at the bottom)
}

The HTML code is as in the accepted answer ;-) Hope this helps anyone, Alex

Documentation examples

Solution 11 - Angular

To add sort programmatically add this on your css.

::ng-deep.mat-header-cell .mat-sort-header-container.mat-sort-header-sorted .mat-sort-header-arrow { opacity: 1 !important; }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJacek KościeszaView Question on Stackoverflow
Solution 1 - AngularAndrew SeguinView Answer on Stackoverflow
Solution 2 - AngularNino FiliuView Answer on Stackoverflow
Solution 3 - AngularAman MadiiarbekovView Answer on Stackoverflow
Solution 4 - AngularsschmidView Answer on Stackoverflow
Solution 5 - AngularMilosView Answer on Stackoverflow
Solution 6 - AngularAlex KlausView Answer on Stackoverflow
Solution 7 - AngularYogesh BorkhadeView Answer on Stackoverflow
Solution 8 - Angularfederico scamuzziView Answer on Stackoverflow
Solution 9 - AngularIlliaView Answer on Stackoverflow
Solution 10 - AngularAlex BView Answer on Stackoverflow
Solution 11 - AngularCarlos Tenorio PérezView Answer on Stackoverflow