I am facing issue in sorting/Filtering date column in PrimeNg Datatable.As i am displaying date "dd/mm/yyyy" string .
- if is use template to display "dd/mm/yyyy" then filter is not working as filter working on actual data bind which is in date ISO format.
- if convert data to string format from the back end then sort is not correct as it sort on string instead of date.
I solved this issue using moment.js, because it's easier and faster, but always code can be customized a little bit if You want to do it without any frameworks (i hope few more if conditions, and string conversions)
So You have to add moment.js to Your project:
a) by adding src link to your main html index file (where is main angular selector, polyfills etc.) from this site https://cdnjs.com/libraries/moment.js/
b) but if it's production i recommend to add it via npm. http://momentjs.com/docs/ here are other possibilities.
Then you must declare moment variable under import statements and above @Component annotation
declare var moment;
then if u already have primeng module added to Your project, in the html file within primeng's p-dataTable tag there is p-column tag and here within this tag we need to add sortable="custom" and (sortFunction)="mysort($event)" like so:
<p-column field="date" header="Data" sortable="custom" (sortFunction)="mysort($event)"></p-column>
Date displayed with p-column tag is in DD.MM.YYYY string format like e.g: 03.01.2017
After that in component where we are fetching and pushing data to array, which is used to display data in a table, in my example named appointments we need to add function named mysort (because we are calling this function in html p-column tag)
mysort(event) {
let comparer = function (a, b): number {
let formatedA = moment(a.date, "DD.MM.YYYY").format('YYYY-MM-DD');
let formatedB = moment(b.date, "DD.MM.YYYY").format('YYYY-MM-DD');
let result: number = -1;
if (moment(formatedB).isBefore(formatedA, 'day')) result = 1;
return result * event.order;
};
this.appointments.sort(comparer);
}
in my example a.date and b.date is a string like "21.12.2016" that we need to format to YYYY-MM-DD. Then we just are comparing dates.
And just it, i checked this code and it works.
I hope it will help someone, and excuse me if explanation was written in tutorial style but this is my first answer and i wanted to do it in the right way :)
I solved it the same way as Relis. However, it didn't work until I reassigned the "this.appointments" variable.
mysort(event) {
this.appointments.sort((appointmentA, appointmentB) => {
// Here the property date is a date string with the format 'dd/mm/yyyy'.
// In the constructor of moment(), the second paramater is
// the format of the string you're passing in.
const momentA = moment(appointmentA.date, 'dd/mm/yyyy');
const momentB = moment(appointmentB.date, 'dd/mm/yyyy');
if(momentB.isBefore(momentA)){
result = 1;
}
return result * event.order;
});
// This is the key here.
this.appointments = [...this.appointments];
}
At first thank @Relis for a helpful answer, even though I've used it to solve a bit different problem.
Regarding the question I believe this could be solved without any additional functions and callbacks that force you to convert date every time header is clicked.
You simply have to separate your model and representation(model for sorting and representation to show data in the data table)
Imagine we have an array of objects with date properties:
let dataArray = [{date:'01/02/2016'},{date:'01/02/2017'}]
Then you could extend every object in this array with additional property sortableDate
:
let dataArray = [{date:'01.02.2016', sortableDate:'2016-02-01'},{date:'01.02.2017', sortableDate:'2017-02-01'}]
For transformation I also suggest to use moment.js. Now you could use one of properties to display value and another to sort:
<p-column [field]="'mySortableDate'" [header]="'Header name' [sortable]="true">
<ng-template let-col let-data="rowData" pTemplate="body">
<span>{{data.date}}</span>
</ng-template>
</p-column>