Norbert Bartko
Norbert Bartko

Reputation: 2632

Default sorting in Angular Material with nested objects

Im using mat table with sorting, where I want to set default sorting on a certain column.

This works for plain attributes but not for nested ones.

Here is my table

<table mat-table [dataSource]="dataSource" multiTemplateDataRows 
       matSort matSortActive="break" matSortDirection="asc"
       class="mat-elevation-z4 w-100">

My nested sorting

this.dataSource.sort = this.sort;
   this.dataSource.sortingDataAccessor = (item, property) => {
   switch(property) {
      case 'break': return item.break.start;
      default: return item[property];
   }
};

Also this nested sorting is fine, when you are manually clicking on the header to sort, it does what I expect but on default it doesn't sort, only shows the sorting arrow.

That's how it looks like on page load:

Here is the corresponding stackblitz.

Upvotes: 3

Views: 6111

Answers (3)

Destro
Destro

Reputation: 11

<ng-container matColumnDef="firstName">
    <th mat-header-cell class="mat-header-sticky" id="firstName" *matHeaderCellDef mat-sort-header tabindex="0"
      [attr.aria-label]="'First Name Tool Tip'" [matTooltip]="tooltipConfiguration['firstName']"
      [matTooltipPosition]="'above'" [matTooltipClass]="'matTooltip-panel'">
      First Name
    </th>
    <td mat-cell *matCellDef="let contact" class="align-center">
      <span class="display-block overflow-ellipsis">
        {{ contact.firstName }}
      </span>
    </td>
</ng-container>

Just use same matColumnDef="firstName" and {{ contact.firstName }} notice that the property .firstName is matching with matColumnDef ID. This is as per angular docs.

Upvotes: 1

Bruno Farias
Bruno Farias

Reputation: 913

Please try the below.


If you want to change the default direction, change it on the ngOnInit method call to this.sortItem

// app.component.ts

import { Component, ViewChild } from '@angular/core';

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

import { interval } from 'rxjs';

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

  public sortedData: any;

  constructor( ) { }

  ngOnInit() {
    setTimeout(() => {         
      this.sortItem({ active: 'break', direction: 'asc' });
    }, 1000);
  }
  compare(a: number | string, b: number | string, isAsc: boolean) {
    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
  }

  sortItem(sort: Sort) {
    const data = DATA_SOURCE.slice();
    if (!sort.active || sort.direction === '') {
      this.sortedData = data;
      return;
    }

    this.sortedData = data.sort((a, b) => {
      const isAsc = sort.direction === 'asc';
      switch (sort.active) {
        case 'break': return this.compare(a.breakTime.start, b.breakTime.start, isAsc);        
        default: return 0;
      }
    });
  }
}

const DATA_SOURCE = [
  {
    name: 'Alice',
    breakTime: {
      start: '14-00',
      end: '14-00'
    },
  },
  {
    name: 'Steve',
    breakTime: {
      start: '10-00',
      end: '11-00'
    },
  },
  {
    name: 'Bob',
    breakTime: {
      start: '12-00',
      end: '13-00'
    },
  },
];

// app.component.html

<table mat-table [dataSource]="sortedData" multiTemplateDataRows 
       matSort (matSortChange)="sortItem($event)" 
       class="mat-elevation-z4 w-100">

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

  <ng-container matColumnDef="break">
    <th mat-header-cell *matHeaderCellDef mat-sort-header > Break </th>
    <td mat-cell *matCellDef="let element">
      {{element.breakTime.start}} - {{element.breakTime.end}}
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let element; columns: displayedColumns;"
      class="element-row"
      [class.example-expanded-row]="expandedElement === element"
      (click)="expandedElement = expandedElement === element ? null : element">
  </tr>
</table>

Upvotes: 0

vadjs
vadjs

Reputation: 355

The initial sorting didn't work properly when i researched it in may.

In my case it was necessary to write my own setSortHeader function that executes after getting data.

setSortHeader() {
  this.sort.active = 'break';
  this.sort.direction = 'desc';
  this.sort.sortChange.emit({ active: this.sort.active, direction: this.sort.direction });

  const sortHeader = this.sort.sortables.get('break');
  if (sortHeader) sortHeader['_setAnimationTransitionState']({ toState: 'active' });
}

I'm not sure that this code still necessary but in my case that worked.

Upvotes: 2

Related Questions