ng2-smart-table icon indicating copy to clipboard operation
ng2-smart-table copied to clipboard

Date Range Filter for date column

Open sahayarex opened this issue 8 years ago • 17 comments
trafficstars

Hi all,

I want to use a date range filter for a date column, How can i do that ?

sahayarex avatar Jul 28 '17 03:07 sahayarex

I think the filter logic has to be provided by you . You can do this by writing an own filterFunction for that column (currently not working when the column-filter control is hidden - see #457).

As I have the subheader hidden in my application I cannot give you a hint for this (if your question goes in this direction).

chriss5 avatar Jul 28 '17 09:07 chriss5

@sahayarex could you put the date-range filter to the ng2-smart-table column ?

yunier0525 avatar Sep 28 '17 19:09 yunier0525

I am trying to set a date range filter, considering issue #457, i still don't know how can I change the template of the filter on the column to accept two values and accordingly filter function to accept three parameters? any idea?

shilan avatar Oct 12 '17 14:10 shilan

no, unfortunately not. I just gave up :(

On Thu, Nov 16, 2017 at 3:05 PM, Kevin Barrientos [email protected] wrote:

@shilan https://github.com/shilan Did you found any solution?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/akveo/ng2-smart-table/issues/459#issuecomment-344932242, or mute the thread https://github.com/notifications/unsubscribe-auth/AH1ZbZEgnHEbIZqqAk9MAd3ZOWB_kbUFks5s3EE9gaJpZM4OmGN- .

shilan avatar Nov 29 '17 14:11 shilan

Same issue here, would be great to have filtering from two or more values

edmondko avatar Dec 19 '17 07:12 edmondko

Hi @sahayarex , you have to go with the implementation of custom-filters.

I implemented the same thing,

image

image

here is my custom filter:

import {Component, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

import { DefaultFilter } from 'ng2-smart-table';
@Component({
  template: `
    <input nbInput placeholder="{{column.title}}" [formControl]="inputControl" [nbDatepicker]="rangepicker">
    <nb-rangepicker #rangepicker></nb-rangepicker>
  `,
  
})
export class DateFilterComponent extends DefaultFilter implements OnInit, OnChanges {
  inputControl = new FormControl();

  constructor() {
    super();
  }

  ngOnInit() {
    this.inputControl.valueChanges
      .pipe(
        distinctUntilChanged(),
        debounceTime(this.delay),
      )
      .subscribe((value: string) => {
        if(this.inputControl.status === 'VALID')
        {
          this.query = value !== null ? JSON.stringify(this.inputControl.value) : "";
          this.setFilter();
        }
      });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.query) {
      this.query = changes.query.currentValue;
      this.inputControl.setValue(this.inputControl.value);
    }
  }
}

and here how I attached it with settings

if(this.attributes[one_opt].datatype == 'datetime64[ns]')
      {
        column_conf['renderComponent']  = DateRenderComponent;
        column_conf["filter"] = {
                                  type: 'custom',
                                  component: DateFilterComponent
                                }
      }

DanishAbsar avatar May 23 '20 08:05 DanishAbsar

Hi @DanishAbsar This looks great but i did not successfully implement this, can you please send some working demo? Thanks!

nebojsajsimic avatar Jun 15 '20 00:06 nebojsajsimic

Hi @DanishAbsar This looks great but i did not successfully implement this, can you please send some working demo? Thanks!

Hello @nebojsajsimic I think i almost put all required code, if you implement the procedure as I stated, then please let me know the error you are getting, or you can share your setting which you feeding in the smart table through .ts

DanishAbsar avatar Jun 17 '20 06:06 DanishAbsar

@DanishAbsar The problem im having is that my date does not get filter, it shows the date in the filter but it doesnt filter between the dates

juanmanuelbasalo avatar Jun 24 '20 22:06 juanmanuelbasalo

@DanishAbsar can you share the code for DateRenderComponent ?

manojnelluri avatar Jul 01 '20 09:07 manojnelluri

@DanishAbsar thanks for the sample code, but I could still not get it working. Are you able to post a working example?

RichardLamb avatar Nov 23 '20 09:11 RichardLamb

I have the example of @DanishAbsar working:

1 Add the ReactiveFormsModule. Webstorm did this for me

This solves Can't bind to 'formControl' since it isn't a known property of 'input'.

2 Now add the DateFilterComponent made by @DanishAbsar. I did not make any changes to it.

import {Component, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

import { DefaultFilter } from 'ng2-smart-table';
@Component({
  template: `
    <input nbInput placeholder="{{column.title}}" [formControl]="inputControl" [nbDatepicker]="rangepicker">
    <nb-rangepicker #rangepicker></nb-rangepicker>
  `,
  
})
export class DateFilterComponent extends DefaultFilter implements OnInit, OnChanges {
  inputControl = new FormControl();

  constructor() {
    super();
  }

  ngOnInit() {
    this.inputControl.valueChanges
      .pipe(
        distinctUntilChanged(),
        debounceTime(this.delay),
      )
      .subscribe((value: string) => {
        if(this.inputControl.status === 'VALID')
        {
          this.query = value !== null ? JSON.stringify(this.inputControl.value) : "";
          this.setFilter();
        }
      });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.query) {
      this.query = changes.query.currentValue;
      this.inputControl.setValue(this.inputControl.value);
    }
  }
}

3 Now add the filter to the settings of your ng-smart-table. Here is a fix I made on the working code of @DanishAbsar. I fixed the filterFunction. I use DateTime from luxon

date: {
        title: 'Date',
        type: 'string',
        filter: {
          type: 'custom',
          component: DateFilterComponent
        },
        filterFunction: (value, query) => {
          const range = JSON.parse(query)
          const start = DateTime.fromISO(range.start)
          const end = DateTime.fromISO(range.end)

          const date = DateTime.fromISO(value)

          return start <= date && date <= end
        },
      }

Thanks @DanishAbsar for bootstrapping my solution. This was highly helpful!

snorberhuis avatar Feb 24 '21 14:02 snorberhuis

@snorberhuis sorry men, can you put it in stackblitz?

JDavid21051 avatar Oct 15 '21 00:10 JDavid21051

@DanishAbsar thanks for the code, but it does not work and I dont get any error. Can you put it in stackblitz ?

smh53 avatar Nov 05 '21 11:11 smh53

I have the example of @DanishAbsar working:

1 Add the ReactiveFormsModule. Webstorm did this for me

This solves Can't bind to 'formControl' since it isn't a known property of 'input'.

2 Now add the DateFilterComponent made by @DanishAbsar. I did not make any changes to it.

import {Component, OnChanges, OnInit, SimpleChanges} from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

import { DefaultFilter } from 'ng2-smart-table';
@Component({
  template: `
    <input nbInput placeholder="{{column.title}}" [formControl]="inputControl" [nbDatepicker]="rangepicker">
    <nb-rangepicker #rangepicker></nb-rangepicker>
  `,
  
})
export class DateFilterComponent extends DefaultFilter implements OnInit, OnChanges {
  inputControl = new FormControl();

  constructor() {
    super();
  }

  ngOnInit() {
    this.inputControl.valueChanges
      .pipe(
        distinctUntilChanged(),
        debounceTime(this.delay),
      )
      .subscribe((value: string) => {
        if(this.inputControl.status === 'VALID')
        {
          this.query = value !== null ? JSON.stringify(this.inputControl.value) : "";
          this.setFilter();
        }
      });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.query) {
      this.query = changes.query.currentValue;
      this.inputControl.setValue(this.inputControl.value);
    }
  }
}

3 Now add the filter to the settings of your ng-smart-table. Here is a fix I made on the working code of @DanishAbsar. I fixed the filterFunction. I use DateTime from luxon

date: {
        title: 'Date',
        type: 'string',
        filter: {
          type: 'custom',
          component: DateFilterComponent
        },
        filterFunction: (value, query) => {
          const range = JSON.parse(query)
          const start = DateTime.fromISO(range.start)
          const end = DateTime.fromISO(range.end)

          const date = DateTime.fromISO(value)

          return start <= date && date <= end
        },
      }

Thanks @DanishAbsar for bootstrapping my solution. This was highly helpful!

Hi @snorberhuis, thanks a lot for the explanation, but I couldn't manage it to work, could you please provide us a stackblitz example? I would really appreciate it.

diegoarndt avatar Feb 22 '22 18:02 diegoarndt

const start = DateTime.fromISO(range.start) const end = DateTime.fromISO(range.end)

      const date = DateTime.fromISO(value)

      return start <= date && date <= end

Hi, I just found out why it was not working.

Since value is an array, you have to change this row: const date = DateTime.fromISO(value[0]);

I'm using the dayjs library here, and it worked pretty smoothly. Using dayjs:

filterFunction: (value, query) => {
  const range = JSON.parse(query);
  const rowDate = value[0];

  return dayjs(range.start).isSameOrBefore(rowDate) && dayjs(rowDate).isSameOrBefore(range.end);
},

diegoarndt avatar Feb 22 '22 21:02 diegoarndt

Hi, This may help Someone. I am attaching the code here.

1. below is the code I create as a separate component and render in the smart table filter. import { Component, EventEmitter, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; import * as moment from 'moment'; import { DefaultFilter } from 'ng2-smart-table'; import { DaterangepickerDirective } from 'ngx-daterangepicker-material'; @Component({ selector: 'datepicker-range', template: <input class="form-control py-2 border-right-0 border search-box" type="text" name="focus" #rangerpicker placeholder="Date Range Filter..." (change)="choosedDate($event)" [locale]="{applyLabel: 'Apply',format: 'DD/MM/YYYY'}" [ranges]="ranges" [showDropdowns]="true" [(ngModel)]="selected" [showCustomRangeLabel]="true" [alwaysShowCalendars]="true" ngxDaterangepickerMd required > <button class="close-icon" type="button" (click)="clearrecord($event)"></button> , styles: [.search-box,.close-icon{ position: relative; } button{ position: relative; } :host::ng-deep div.md-drppicker { position: fixed; font-family: Roboto,sans-serif; color: green; border-radius: 4px; padding: 4px; overflow: hidden; z-index: 1; font-size: 14px; background-color: #fff; } .close-icon { border:1px solid transparent; background-color: transparent; display: inline-block; vertical-align: middle; outline: 0; cursor: pointer; position: absolute; } .close-icon:after { content: "X"; display: block; width: 30px; height: 34px; position: absolute; background-color: #007bff; z-index: 1; right: -145px; top: -35px; bottom: 0; margin: 0px 43px 0px 0px; padding: 6px; color: black; font-weight: normal; font-size: 12px; cursor: pointer; } @media only screen and (max-device-width: 480px) { .close-icon:after { content: "X"; display: block; width: 20px; height: 32px; position: absolute; background-color: #007bff; z-index: 1; right: -48px; top: -37px; bottom: 0; margin: auto; padding: 6px; color: black; font-weight: normal; font-size: 12px; cursor: pointer; } } .search-box:not(:valid) ~ .close-icon { display: none; } ] }) export class DatepickerRangeComponent extends DefaultFilter implements OnChanges { @ViewChild(DaterangepickerDirective, { static: true }) picker: DaterangepickerDirective; @Output() filter: EventEmitter = new EventEmitter(); selected: { startDate: moment.Moment, endDate: moment.Moment }; ranges: any = { 'Today': [moment(), moment()], 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], 'Last 7 Days': [moment().subtract(6, 'days'), moment()], 'Last 30 Days': [moment().subtract(29, 'days'), moment()], 'This Month': [moment().startOf('month'), moment().endOf('month')], 'Last Month': [ moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month') ] };

ngOnChanges(changes: SimpleChanges) {
    if (changes.query) {
        this.query = changes.query.currentValue;
    }
}

choosedDate(event) {
    var startDate = new Date(moment(event.startDate).format('YYYY-MM-DD')).getTime();
    var endDate = new Date(moment(event.endDate).format('YYYY-MM-DD'));
    endDate.setHours(23, 59, 59, 999)
    var searchDate = startDate + '-' + endDate.getTime();
    this.filter.emit(searchDate);
}

clearrecord(event) {
    this.picker.clear();
    this.filter.emit(event);
}

}

2. add filter emitter in Html and called in ts file like point 3. <ng2-smart-table [settings]="settings" [source]="source" (filter)="filterDateRange($event)">

3. add the filter function like below, UploadDate: { title: 'Uploaded Date', sort: true, sortDirection: 'desc', valuePrepareFunction: (UploadDate: Date) => { return this.datePipe.transform(UploadDate, 'dd/MM/yyyy'); }, filter: { type: 'custom', component: DatepickerRangeComponent }, filterFunction: (cell?: any, search?: string) => { if (search.length > 0) { const dates = search.split('-'); var startDate = parseInt(dates[0]); var endDate = parseInt(dates[1]); var date = new Date(cell).getTime(); return (date >= startDate && date <= endDate); } else return 'N/A'; } }

4. Added screenshot below. image image

karthikrajats avatar May 10 '22 09:05 karthikrajats