jbox-web/ajax-datatables-rails

Argument out of range error with date_range cond

clveranis opened this issue · 1 comments

I recently implemented a date_range filter using YADCF and while the date range filter itself works fine, I receive the following error if I try to use the native search input:

Completed 500 Internal Server Error in 7ms (ActiveRecord: 1.7ms)
ArgumentError (argument out of range):

I have them implemented like such:

View_columns:

def view_columns
    @view_columns ||= {
      ...
      submitted_on: { source: "Order.created_at", cond: :date_range,  delimiter: '-yadcf_delim-',
      ...
    }
end

YADCF JS Initialization:

yadcf.init(tableElement.DataTable(), [{
  column_number : 11, 
  filter_type: "range_date", 
  datepicker_type: 'bootstrap-datetimepicker', 
  date_format: 'YYYY-MM-DD', 
  filter_container_id: 'yadcfDateDiv'
}]);

I don't mind setting the date column to be searchable: false to disable the search feature (which removes the error) but then the date range filter stops working. Any ideas would be greatly appreciated, thanks!

So my work around for this was adding 2 initializers to my rails app:

  • datetime_ext.rb: to add a parsable? method to the Ruby Time class to check if the search string is a valid datetime
  • ajax_datatable_rails.rb: to overwrite the non_regex_search method when the column is set to cond: :date_range

### config/initializers/datetime_ext.rb ###

class Time
  def self.parsable?(string)
    begin
      parse(string)
      true
    rescue ArgumentError
      false
    end
  end
end
### config/initializers/ajax_datatables_rails.rb ###

module AjaxDatatablesRails
  module Datatable
    class Column
      module Search
        def non_regex_search
          case cond
          when Proc
            filter
          when :eq, :not_eq, :lt, :gt, :lteq, :gteq, :in
            searchable_integer? ? raw_search(cond) : empty_search
          when :start_with
            text_search("#{formatted_value}%")
          when :end_with
            text_search("%#{formatted_value}")
          when :like
            text_search("%#{formatted_value}%")
          when :string_eq
            raw_search(:eq)
          when :string_in
            raw_search(:in)
          when :null_value
            null_value_search
          when :date_range

            if Time.parsable?(formatted_value)
              date_range_search
            else
              text_search("%#{formatted_value}%")
            end

          end
        end
      end
    end
  end
end


The idea is to check if the searched string is a valid datetime format and can be parsed into a valid Time object, if it's not, then the search function treats the column as if its searching it as a regular string (i.e. if cond: :datetime was not explicitly set). This way you can search against that column as either a string or date time.

One additional thing I noticed is that if you are using the bootstrap-datetimepicker option with YADCF and you clear the date inputs manually (without using the red 'X' button that YADCF creates), then it will submit the search string -yadcf_delim- to the filter search, thus causing your table to search for a date value matching that delim string. My workaround for that was:

### In some .js file where you have yadcf.init() ###

var dateRanges = $('#yadcf-filter--orders-datatable-from-date-11,#yadcf-filter--orders-datatable-to-date-11');
dateRanges.each(function() {
    $(this).on('dp.hide', function(e){
      if (dateRanges[0].value.length === 0 && dateRanges[1].value.length === 0) {
        yadcf.doFilter('clear', '-orders-datatable', 11, 'range_date');
      }
    });
});

I'm aware this is a bit 'hacky' and I'm sure there is probably a more elegant way to do all of the above but this is where I landed and my table is functioning as desired. Maybe this will help some future Googler or if anyone has any feedback on a better way to do this then I'm all ears. Happy coding!