user9750148
user9750148

Reputation: 395

Angular 6 - PrimeNG - how to sort column by Date?

I have a code in Angular - PrimeNG and trying to make sorting by date (one of the columns):

<p-table
  [columns]="cols"
  [value]="questions"
  selectionMode="single"
  [(selection)]="selectedQuestion"
  (onRowSelect)="onRowSelect($event)"
  [paginator]="true"
  [rows]="20">

  <ng-template pTemplate="header" let-columns>
    <tr>
      <th *ngFor="let col of columns">
      </th>
    </tr>
  </ng-template>

  <ng-template 
    pTemplate="body" 
    let-rowData 
    let-columns="columns">
    <tr [pSelectableRow]="rowData">
      <td *ngFor="let col of columns">
        {{rowData[col.field]}}
      </td>
    </tr>
  </ng-template>

</p-table>

One of the columns dates are:
6/26/18
7/26/17

How to sort by Date instead of by String?

Thanks.

Upvotes: 1

Views: 9264

Answers (2)

nicktehhero
nicktehhero

Reputation: 21

HTML:

<p-dataTable
    [value]="table.rows"
    (onSort)="sortColumn($event)">

    <p-column
        *ngFor="let column of table.columns"
        [field]="column.field"
        [header]="column.header"
        sortable="custom"> 
    // All your columns and stuff and your data and all that </p-column>

</p-dataTable>

TS:

// Add this line at the end of your imports, before the @Component annotation:
import * as moment from 'moment';
// If that doesn't work, you may have to add this instead:
const moment = require('moment');

// Then, in your component body add this:

public dateFieldFormat:string = 'MM/DD/YYYY';
public table; //Assuming this is the data you're passing in. Some sort of JSON with an array of rows and an array of columns

isDateColumn(columnTitle: string) {
    for (const row of this.table.rows) {
      const value = row[columnTitle];
      if (!moment(value, this.dateFieldFormat).isValid() && value !== null) {
        return false;
      }
    }
    return true;
}

sortColumn(eventPayload: any): void {
    this.sort(eventPayload);
    this.table.rows = [...this.table.rows];
}

sort(event: any): Array<any> {
    return this.table.rows.sort((item1, item2) => {
      const value1: string = item1[event.field];
      const value2: string = item2[event.field];

      if (value1 === null) {
        return 1;
      }

      if (this.isDateColumn(event.field)) {
        const date1 = moment(value1, this.dateFieldFormat);
        const date2 = moment(value2, this.dateFieldFormat);

        let result: number = -1;
        if (moment(date2).isBefore(date1, 'day')) { result = 1; }

        return result * event.order;
      }

      let result = null;

      if (value1 == null && value2 != null) {
        result = -1;
      } else if (value1 != null && value2 == null) {
        result = 1;
      } else if (value1 == null && value2 == null) {
        result = 0;
      } else if (typeof value1 === 'string' && typeof value2 === 'string') {
        result = value1.localeCompare(value2);
      } else {
        result = (value1 < value2) ? -1 : (value1 > value2) ? 1 : 0;
      }

      return (event.order * result);
    });
}

primeng 4.3.0

Angular 4.3.6

also using MomentJS which is easy to use :)

I created this myself and have used it extensively. What it does, is when you sort the column, it checks to see whether or not the column you're trying to sort ONLY has dates. And if it does, it will use MomentJS to check values based on chronology. Otherwise it will sort alphabetically. The code for sorting alphabetically comes directly from the primeNG source code, so don't worry about it not functioning correctly :)

Also, if you column with dates has some null values in it, those will always be at the bottom, no matter how you sort, up or down.

Thanks also to the lads in this question: PrimeNG DataTable Custom Sorting or filtering (Angular 2) for starting me out.

Hopefully I've made this clear. Let me know how I can improve my answer if it's unclear, or it doesn't work for you.

Upvotes: 1

Dierp
Dierp

Reputation: 321

I've added a rule made with MomentJs and it worked fine form me. It resolved my problem when I was trying to sort the columns with any type of data or string.

if (value1 == null && value2 != null) {
    result = -1;
  } else if (value1 != null && value2 == null) {
    result = 1;
  } else if (value1 == null && value2 == null) {
    result = 0;
  } else if (typeof value1 === 'string' && typeof value2 === 'string') {

    let test = value1.substr(2,1)

    let date1 = moment(value1, 'DD-MM-YYYY')
    let date2 = moment(value2, 'DD-MM-YYYY')
    if(test == '-' || test == '/'){
      result = date1.diff(date2, 'days')
    }else{
      result = value1.localeCompare(value2);
    }

  }else {
    result = (value1 < value2) ? -1 : (value1 > value2) ? 1 : 0;
  }

Upvotes: 1

Related Questions