Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
31
rated 0 times [  37] [ 6]  / answers: 1 / hits: 18980  / 11 Years ago, thu, february 27, 2014, 12:00:00

I feel like I could use another pair of eyes on my code right now.



I am using jQuery UI's Datepicker to grab dates from two html inputs:



<!-- HTML inputs -->
<p id=date_filter>
<span id=date-label-from class=date-label><?php echo LANG_FROMDATE; ?>: </span><input class=date_range_filter date type=text id=datepicker_min /><img id=calender-from class=datepicker-calender src=includes/js/jquery/jquery-ui/img/calendar.png width=17px height=18px />
<span id=date-label-to class=date-label><?php echo LANG_TODATE; ?>: </span><input class=date_range_filter date type=text id=datepicker_max /><img id=calender-to class=datepicker-calender src=includes/js/jquery/jquery-ui/img/calendar.png width=17px height=18px />
<button class=btn id=reset_btn><?php echo LANG_RESET; ?></button>
</p>


That calender img tag is just an icon that also triggers the datepicker, i.e. like this:



$(document).ready(function() {
$('#calender-from').click(function() {
$(#datepicker_min).datepicker(show);
});
$('#calender-to').click(function() {
$(#datepicker_max).datepicker(show);
});
});


So that's the basic stuff that's all good. The issue I'm having is I have written javascript that is an extension to the DataTables filtering api. I wrote my code based on this example: https://datatables.net/examples/plug-ins/range_filtering.html



The problem is right now my code is only working in Google Chrome and fails in FireFox, Safari, and Internet Explorer. I probably am just missing something small or have some minor semantic mistake in my code.



I extend the DataTables filtering API like this:



// Date range filter
var minDateFilter = ;
var maxDateFilter = ;

$.fn.dataTableExt.afnFiltering.push(
function( oSettings, aData, iDataIndex ) {
if ( typeof aData._date == 'undefined' ) {
aData._date = new Date(aData[0]).getTime();
}

if ( minDateFilter && !isNaN(minDateFilter) ) {
if ( aData._date < minDateFilter ) {
return false;
}
}

if ( maxDateFilter && !isNaN(maxDateFilter) ) {
if ( aData._date > maxDateFilter ) {
return false;
}
}

return true;
}
);


This way seems to return false in other browsers because I will get a result of Showing 1 - 50 of 67 records regardless of what data I have in the datapicker inputs.



I'm handling the jQuery UI Datepicker inputs like this:



$(document).ready(function() {
$(#datepicker_min).datepicker({
onSelect: function(date) {
minDateFilter = new Date(date).getTime();
oTable.fnDraw();
}
}).keyup(function(){
minDateFilter = new Date(this.value).getTime();
oTable.fnDraw();
});

$( #datepicker_max ).datepicker( {
onSelect: function(date) {
maxDateFilter = new Date(date).getTime();
oTable.fnDraw();
}
}).keyup(function(){
maxDateFilter = new Date(this.value).getTime();
oTable.fnDraw();
});
});


I also tried extending the filter API like this (to be closer to original DataTables example):



$.fn.dataTableExt.afnFiltering.push(
function( oSettings, aData, iDataIndex ) {
var iMin = minDateFilter;
var iMax = maxDateFilter;
var iDate = new Date(aData[0]).getTime();
if ( iMin == && iMax == )
{
return true;
}
else if ( iMin == && iDate < iMax )
{
console.log(iDate 1 = +iDate);
return true;
}
else if ( iMin < iDate && == iMax )
{
console.log(iDate 2 = +iDate);
return true;
}
else if ( iMin < iDate && iDate < iMax )
{
console.log(iDate = 3 +iDate);
return true;
}
return false;
}
);


When I do it this way I get a somewhat similar result of my filter code working correctly only in Chrome, and in the other browsers I'll get a result of Showing 0 to 0 records (filtered from 67 total records) so here it returns true but it filters incorrectly - i.e. it shows 0 results after filtering regardless of what values are in the datepicker inputs.



Ugh! why is my code only working in Google Chrome and not working in other browsers (Safari, IE, FireFox)?? Any help is appreciated, thanks in advance!


More From » jquery

 Answers
18

After all this time I actually finally found out what causes this issue.


Turns out it is an issue with javascript date time objects being parsed differently in different browsers.


So, in order to make your filters fully cross browser friendly, you just need to use date format in your jQuery UI datepicker that works for all broswers to parse dates from using JS new Date(date_var). But that's easier said than done. What I do is manipulate the date time value before sending it through the custom Datatables filter.


See below for the most recent cross browser implementation I've made. It's overall a better implementation than what is in my question because you don't need to worry as much about the filtering api extension it is handled automatically by the function. See the comments in the code itself for an example where I manipulate the date format to work nicely in Safari's date.parse(dateString) syntax.


$(document).ready( function () {
// define vars
var dTable = $('#transactions'),
date_from = null,
date_to = null,
dateRangeFromSearchBox = $('#date_from_range_search'),
dateRangeToSearchBox = $('#date_to_range_search'),
dateRangeResetButton = $('#date_range_reset_button');

// bootstrap our datatable
dTable.DataTable();

// bootstrap datepickers
$('input.datepicker').datepicker({
dateFormat: 'yy-mm-dd',
onSelect: function (date) {
date_from = new Date( dateRangeFromSearchBox.val() ).getTime();
date_to = new Date( dateRangeToSearchBox.val() ).getTime();
// force change event
dateRangeFromSearchBox.trigger('change');
dateRangeToSearchBox.trigger('change');
// disable further if filtering occured
if (!isNaN(date_from) &&
!isNaN(date_from) &&
dateRangeFromSearchBox.val().length > 0 &&
dateRangeToSearchBox.val().length > 0) {
dateRangeFromSearchBox.prop('disabled', true);
dateRangeToSearchBox.prop('disabled', true);
}
}
});

// date range search
// date from
dateRangeFromSearchBox.change( function () {
if (date_from === "" ||
date_to === "" ||
dateRangeFromSearchBox.val().length === 0 ||
dateRangeToSearchBox.val().length === 0) {
//console.log('reset event from box');
dTable_filterColumnByDateRange (dTable, 1, '', '');
// exit asap if date is invalid
} else if ( isNaN(date_from) || isNaN(date_to) ) {
//console.log('nan event from box')
return;
} else {
//console.log('filter event from box');
// we good? let's filter
dTable_filterColumnByDateRange (dTable, 1, date_from, date_to);
}
});

// date to
dateRangeToSearchBox.change( function () {
if (date_from === "" ||
date_to === "" ||
dateRangeFromSearchBox.val().length === 0 ||
dateRangeToSearchBox.val().length === 0) {
//console.log('reset event to box');
dTable_filterColumnByDateRange (dTable, 1, '', '');
// exit asap if date is invalid
} else if ( isNaN( new Date( dateRangeToSearchBox.val() ).getTime() ) || isNaN(date_from) ) {
//console.log('nan event to box')
return;
} else {
//console.log('filter event from box');
// we good? let's filter
dTable_filterColumnByDateRange (dTable, 1, date_from, date_to);
}
});

//date range reset
dateRangeResetButton.click( function () {
//console.log('reset event');
// this part is crazy
// don't worry I know it is
$('#date_from_range_search').val('').promise().done( function () {
$(this)
.trigger('change')
.prop('disabled', false);
$('#date_to_range_search').val('').promise().done( function () {
$(this)
.trigger('change')
.prop('disabled', false);
});
});
});
});

// and now here is our worker function
// which the above dom ready code is calling:
/**
* Filters a single column based on two date range values
* @param {Object} data_table - jQuery html object instance of the table
* @param {Integer} column_index - DataTables int value of date column to filter
* @param {Integer} date_from - unix time stamp of start date to filter between
* @param {Integer} date_to - unix time stamp of end date to filter between
*/
dTable_filterColumnByDateRange = function (data_table, column_index, date_from, date_to) {
var rowValue_asTimeStamp = null;

data_table
.DataTable()
.column()
.data()
.filter( function (value, index) {
rowValue_asTimeStamp = new Date(value).getTime();

// debug:
//console.log('from', date_from);
//console.log('to', date_to);
//console.log('row', rowValue_asTimeStamp);
//console.log('existing filters?', $.fn.dataTableExt.afnFiltering.length);
if (date_to == null ||
date_to == "" ||
date_from == null ||
date_from == "") {
$.fn.dataTableExt.afnFiltering.pop();
var returnVal = true;
} else {
var returnVal = (rowValue_asTimeStamp >= date_from && rowValue_asTimeStamp <= date_to) ? true : false;
}
})
.draw();

// extend the filter API in the
// most annoying way possible
$.fn.dataTableExt.afnFiltering.push(
function (oSettings, aData, iDataIndex) {
// built in reset?
if (date_to == null ||
date_to == "" ||
date_from == null ||
date_from == "") {
//console.log(aData[column_index]);
return true;
} else {
// debug:
//console.log('arg 1', (new Date(aData[column_index])).getTime());
//console.log('date from', date_from);
//console.log('date to', date_to);
//console.log('truth condition', ((new Date(aData[column_index])).getTime() > date_from && (new Date(aData[column_index])).getTime() < date_to));
/**
* THIS PART MAKES THE FILTER WORK IN SAFARI :)
*/
var parsed = aData[column_index].replace(' ', 'T');
return ((new Date( parsed )).getTime() > date_from && (new Date( parsed )).getTime() < date_to);
}
}
);
};


The above example is intended to work for columns that use a timestamp column value like: <td>2016-08-05 19:14:00</td>


[#72257] Thursday, February 27, 2014, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
grant

Total Points: 169
Total Questions: 96
Total Answers: 98

Location: Cape Verde
Member since Sat, Apr 24, 2021
3 Years ago
;