Reputation: 499
I have this simple app (as the demonstration only) that is using material angular framework to provide the component that is sorting the embeded array of data (ScheduleDateTime
).
Problem with this app is that when I programmatically trigger sortation by executing the code this.sort.sort(({ id: 'date', start: 'asc' }) as MatSortable);
the result is really convoluted. It is supposed to be sorted by first column - which is Date - but it seems to sort it by the first value of the Date column (DD
part of DD-MM-yyyy HH:mm
).
Can somebody spot what am I doing wrong?
This is my app.component.ts:
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, MatSortable, Sort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import * as moment from 'moment';
import { timer } from 'rxjs';
export interface SortableDate {
date: string
}
export class ScheduleDateTime {
id!: string;
date!: string;
highlighted! : boolean;
}
const COLUMNS_SCHEMA = [
{
key: "date",
type: "text",
label: "Date"
},
]
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
@ViewChild('paginator') paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort;
title = 'TableTest';
displayedColumns: string[] = COLUMNS_SCHEMA.map((col) => col.key);
columnsSchema: any = COLUMNS_SCHEMA;
dataSource!: MatTableDataSource<ScheduleDateTime>;// = new MatTableDataSource();
futureScheduleDate: ScheduleDateTime[] = [];
constructor(
private changeDetector: ChangeDetectorRef
) { }
ngOnInit(): void {
this.dataSource = new MatTableDataSource();
}
ngAfterViewInit(): void {
timer(0).subscribe(() => {
this.futureScheduleDate = this.getTestData();
this.dataSource.data = this.futureScheduleDate;
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
// Initial sorting by date
this.sort.sort(({ id: 'date', start: 'asc' }) as MatSortable);
})
}
sortData(sort: Sort) {
AppComponent.sortMethod(this.futureScheduleDate, sort);
this.dataSource.data = this.futureScheduleDate;
this.changeDetector.detectChanges();
}
getTestData(): ScheduleDateTime[] {
var retVal =
[
{
id: '',
date: "24-03-1961",
highlighted: false
},
{
id: '',
date: "25-03-1961",
highlighted: false
},
{
id: '',
date: "26-03-1961",
highlighted: false
},
{
id: '',
date: "27-03-1961",
highlighted: false
},
{
id: '',
date: "24-04-1961",
highlighted: false
},
{
id: '',
date: "25-04-1961",
highlighted: false
},
{
id: '',
date: "26-04-1961",
highlighted: false
},
{
id: '',
date: "27-04-1961",
highlighted: false
}
];
return retVal;
}
static sortMethod(dateSort: SortableDate[], sort: Sort) {
if (!sort.active || sort.direction == '') {
return;
}
console.log(sort);
dateSort.sort((a, b) => {
let isAsc = sort.direction == 'asc';
var date1 = moment(a.date, 'DD-MM-yyyy HH:mm').toDate().getTime();
var date2 = moment(b.date, 'DD-MM-yyyy HH:mm').toDate().getTime();
if (date1 < date2) {
console.log("date1 is earlier than date2");
return isAsc ? -1 : 1;
} else if (date1 > date2) {
console.log("date1 is later than date2");
return isAsc ? 1 : -1;;
} else {
console.log("date1 and date2 are the same");
return 0;
}
});
}
}
And this is my template class app.component.html:
<mat-table #table [dataSource]="dataSource" matSort (matSortChange)="sortData($event)" style="min-width: 800px;">
<ng-container matColumnDef="date">
<mat-header-cell *matHeaderCellDef mat-sort-header> Date </mat-header-cell>
<mat-cell *matCellDef="let schedule">
<input type="text" matInput [value]="schedule.date" readonly>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;let i = index;"
[ngClass]="{hovered: row.hovered, highlighted: row.highlighted}" #tr (mouseover)="row.hovered = true"
(mouseout)="row.hovered = false"></mat-row>
</mat-table>
<mat-paginator #paginator pageSize='10' [length]="futureScheduleDate.length" [pageSizeOptions]="[1, 30, 50, 100]"
showFirstLastButtons>
</mat-paginator>
Upvotes: 0
Views: 101
Reputation: 58019
To define a custom sort you need change the sortData function of the MatTableDataSource
this.dataSource.sortData =(data: ScheduleDateTime [], sort: MatSort) => {
const factor =
sort.direction == "asc" ? 1 : sort.direction == "desc" ? -1 : 0;
switch(sort.active)
{
case "date":
..here your function sort...
return data.sort((a,b)=>....)
break;
}
return data.sort((a,b)=>a[sort.active]>b[sort.active]? factor:
-1*factor:0
}
}
There are another approach to the problem of sort dates (or what-ever non standard). Create a new column with the date formatted and sort by this "field")
If you write
this.dataSource.data = this.futureScheduleDate.map(x=>({
...x,
dateFormatted:moment(a.date, 'DD-MM-yyyy HH:mm').toDate().getTime()
}));
You can simply indicate in the sort-header the "field"
<mat-header-cell *matHeaderCellDef mat-sort-header="dateFormatted">
Date
</mat-header-cell>
Upvotes: 0