My DataTables date range filter using jQuery UI Datepicker works only in Google Chrome - javascript

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!

I have created a plunker from your script and added some made up html table. I used as much of your code as possible but had to adjust some of your ids.
I'm not sure where along the way i made changes that finally got this working, but I guess its mainly related to your filter variables being not global.
// Date range filter
minDateFilter = "";
maxDateFilter = "";
instead of:
// Date range filter
var minDateFilter = "";
var maxDateFilter = "";
Have a look at this Plunker with the full code which runs perfectly on FF 27.0.1 and find out for yourself.
Update:
Simplified the datepicker initialisition to this:
$("#datepicker_from").datepicker({
showOn: "button",
buttonImage: "images/calendar.gif",
buttonImageOnly: false,
"onSelect": function(date) {
minDateFilter = new Date(date).getTime();
oTable.fnDraw();
}
}).keyup(function() {
minDateFilter = new Date(this.value).getTime();
oTable.fnDraw();
});
This prevents the double assignement of the widget you have done in:
$('#calender-from').click(function() {
$("#datepicker_min").datepicker("show");
});
and:
$("#datepicker_min").datepicker({
"onSelect": function(date) {
minDateFilter = new Date(date).getTime();
oTable.fnDraw();
}
Now it uses its native function to diplay an icon.
Maybe some browser are picky about this.
Updated Plunker

Here is the script that worked for me.
$.fn.dataTableExt.afnFiltering.push(
function(oSettings, aData, iDataIndex){
var dateStart = parseDateValue($("#dateStart").val());
var dateEnd = parseDateValue($("#dateEnd").val());
var evalDate= parseDateValue(aData[5]);
var evalDate1= parseDateValue(aData[6]);
if ((evalDate >= dateStart && evalDate <= dateEnd)||(evalDate1 >= dateStart && evalDate1 <= dateEnd)) {
return true;
}
else {
return false;
}
});`

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>

Related

How to add one and more leaves in jquery datepicker

I add leave in datepicker using array but, two leave is on same day is not showing in calendar only first leave in array is showing but second leave is not showing.
my var leaveday array is like this = "2021,09,28,Love is on Leave-2021,09,18,Pravin is on Leave-2021,09,25,Darshit is on Leave-2021,09,18,Love is on Leave-"
my jquery is here
var leave_dates= $("#all_past_leave").val();
if(leave_dates !== null && leave_dates !== '' && leave_dates !== undefined) {
var leave_all = leave_dates.slice(0,-1);
var leaveDays = leave_all.split('-');
}
$(function() {
$("#past_leave").datepicker({
numberOfMonths:3,
beforeShowDay: setLeaveDays
});
// set Leave function which is configured in beforeShowDay
function setLeaveDays(date) {
for (i = 0; i < leaveDays.length; i++) {
var leaveData = leaveDays[i].split(',');
if (date.getFullYear() == leaveData[0]
&& date.getMonth() == leaveData[1] - 1
&& date.getDate() == leaveData[2]) {
return [true, 'staff_leaves', leaveData[3]];
}
}
return [true, ''];
}
});
I am getting result like this see image here
but I want result like this I edited from chrome inspect for example see image here

How do I combine multiple datepicker parameters into one Gravity Forms script?

I'm trying to customize the datepicker within Gravity Forms so that users cannot pick weekends and also add some blackout days throughout the year. I can get each individual parameter to work, but I have no idea how to combine them into one script, and running two scripts doesn't work either. Can you please help me out? I'm clueless with Javascript and am surprised I got this far.
Script 1: No Weekends
<script>
gform.addFilter( 'gform_datepicker_options_pre_init', function( optionsObj, formId, fieldId ) {
if ( formId == 3 && fieldId == 7 ) {
optionsObj.firstDay = 1;
optionsObj.beforeShowDay = jQuery.datepicker.noWeekends;
}
return optionsObj;
});
</script>
Script 2: Disable certain days
<script>
gform.addFilter( 'gform_datepicker_options_pre_init', function( optionsObj, formId, fieldId ) {
if ( formId == 3 && fieldId == 7 ) {
var disabledDays = ['09/15/2021', '09/16/2021', '09/17/2021'];
optionsObj.beforeShowDay = function(date) {
var checkdate = jQuery.datepicker.formatDate('mm/dd/yy', date);
return [disabledDays.indexOf(checkdate) == -1];
};
}
return optionsObj;
});
</script>
I pulled this info from here: https://docs.gravityforms.com/gform_datepicker_options_pre_init/#5-disable-specific-dates
Thanks for any help!
gform.addFilter('gform_datepicker_options_pre_init', function (optionsObj, formId, fieldId) {
if ( formId == 3 && fieldId == 7 ) {
optionsObj.firstDay = 1;
optionsObj.beforeShowDay = function (date) {
var disabledDays = ['09/15/2021', '09/16/2021', '09/17/2021'],
currentDate = jQuery.datepicker.formatDate('mm/dd/yy', date),
day = date.getDay();
return [!(disabledDays.indexOf(currentDate) != -1 || day == 0 || day == 6 )];
};
}
return optionsObj;
});

Validate Null value in Ext JS javascript

I need to allow for the value 's1pdtCalc' to be null and allow for the record to be saved.
Right now I get the error message "s1pdtCalc is null or not an object". Thanks for the help and here is the code.
function validateForm(values) {
var pass = true;
// check percent days turnaround
var ck = values.s1pdtCalc.toString ();
if (ck > "") {
var t1 = values.s1pdtNTTd.toString (); //NEMIS Turn around
var t2 = values.s1pdtTAd.toString (); //NEMIS Turn adjustment
var t3 = values.actDays.toString (); //NEMIS Turn adjustment
t1 = (t1!=null?t1.trim ():0);
if (ck == "MINUS") {
if ((t1-t2) > t3) {
errorMsgs += '<br /> s1pdtATT - Percent days turnaround < 4.0.0. exceeds the number of activation days';
}
}
else {
if ((t1+t2) > t3) {
errorMsgs += '<br /> s1pdtATT - Percent days turnaround < 4.0.0. exceeds the number of activation days';
}
}
}
if (errorMsgs > "") {
pass = false
}
return pass;
}
You can't invoke methods on objects that don't exist. You'd need to default the s1pdtCalc to something if it doesn't exist before attempting to invoke methods:
function validateForm(values) {
...
// set ck to an empty string if values.s1pdtCalc doesn't exist
var ck = values.s1pdtCalc ? values.s1pdtCalc.toString() : '';
...

how to convert mouse events and touch events using java script

Any idea about about how to use double click event in tablets or ipad. Like 'onmousedown' is equivalent to 'touchstart'.
maybe the hammer.js library for multi-touch gestures could interest you too: http://eightmedia.github.com/hammer.js/
I guess a quick google search would solve your problem, the short answer is yes there are. the long answer is you better of using a framework like jQuery-mobile can handle that for you, giving you ontouch, scroll etc events..
also look into energize.js that make those clicks events faster
also similiar to this stackvoverflow answer
To Detect long press you can simply use like this.
<div id="element" style="width:200px;height:200px; border:1px solid red;"> </div>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
<!------------ Javascript Code ---------->
$('#element').each(function() {
var timeout, longtouch;
$(this).mousedown(function() {
timeout = setTimeout(function() {
longtouch = true;
}, 1000);
}).mouseup(function() {
if (longtouch) {
alert('long touch');
} else {
alert('short touch');
}
longtouch = false;
clearTimeout(timeout);
});
});​
Aged topic, but not marked as answered yet, so I thought I'd give it a shot.
For most cases, a JavaScript framework that adds an abstraction layer to the events would help. (As others have pointed out.) But for the cases where you can't, try this.
var el = document.getElementById('myelement');
var numClicks = 0; // count the number of recent clicks
var lastClickTime = 0; // time of last click in milliseconds
var threshold = 50; // you need to set this to a reasonable value
function isDoubleClick() {
var r;
if( numClicks == 0 ) {
numClicks++; // first click never counts
r = false;
} else if( new Date().getTime() - lastClickTime > threshold ) {
numClicks = 1; // too long time has passed since lsat click, reset the count
r = false;
} else {
numClicks++; // note: reset numClicks here if you want to treat triple-clicks and beyond differently
r = true;
}
lastClickTime = new Date().getTime();
return r;
}
var myClickFunction = function (event) {
if( isDoubleClick() ) {
// your double-click code
} else {
// plain click code
}
}
// bind your own click function to the mouse click event
el.addEventListener("mouseclick", myClickFunction, false);
Try to implement doubleTap you can use this code.
(function($){
// Determine if we on iPhone or iPad
var isiOS = false;
var agent = navigator.userAgent.toLowerCase();
if(agent.indexOf('iphone') >= 0 || agent.indexOf('ipad') >= 0){
isiOS = true;
}
$.fn.doubletap = function(onDoubleTapCallback, onTapCallback, delay){
var eventName, action;
delay = delay == null? 500 : delay;
eventName = isiOS == true? 'touchend' : 'click';
$(this).bind(eventName, function(event){
var now = new Date().getTime();
var lastTouch = $(this).data('lastTouch') || now + 1 /** the first time this will make delta a negative number */;
var delta = now - lastTouch;
clearTimeout(action);
if(delta<500 && delta>0){
if(onDoubleTapCallback != null && typeof onDoubleTapCallback == 'function'){
onDoubleTapCallback(event);
}
}else{
$(this).data('lastTouch', now);
action = setTimeout(function(evt){
if(onTapCallback != null && typeof onTapCallback == 'function'){
onTapCallback(evt);
}
clearTimeout(action); // clear the timeout
}, delay, [event]);
}
$(this).data('lastTouch', now);
});
};
})(jQuery);
and to use doubleTap event
$(selector).doubletap(
/** doubletap-dblclick callback */
function(event){
alert('double-tap');
},
/** touch-click callback (touch) */
function(event){
alert('single-tap');
},
/** doubletap-dblclick delay (default is 500 ms) */
400
);
I tried something like this :
<------java script and jquery ------>
var startTime,endTime;
$('#main-content').mousedown(function(event){
startTime = new Date().getTime();
//any other action
});
$('#main-content').mouseup(function(event){
endTime = new Date().getTime();
if(isTouchDevice()){
if((endTime-startTime)>200 && (endTime-startTime)<1000 ){
alert('long touch')
}
}
});
function isTouchDevice(){
return (typeof(window.ontouchstart) != 'undefined') ? true : false;
}

Select portion of input/string instead of all of it

I have an input that holds a date value like so
03/15/2012
I am trying to select only portions of the the value instead of the whole thing. For instance if I click the spot before 2 in 2012 the year 2012 will be selected not the whole date (same for is true for months and day).
This is the code I am working with now
html:
<input class = "date-container" />
javascript/jquery:
$('.date-container').on('select', function (e)
e.preventDefault()
this.onselectstart = function () { return false; };
})
$('.date-container').on('focus', function ()
{
if (document.selection) {
this.focus();
var Sel = document.selection.createRange();
Sel.moveStart('character', -this.value.length);
CaretPos = Sel.text.length;
}
// Firefox support
else if (this.selectionStart || this.selectionStart == '0')
switch (this.selectionStart) {
case 0:
case 1:
this.selectionStart = 0;
this.selectionEnd = 1;
break;
}
}
I have tried a couple things so far. The code above is attempting to prevent the normal select action then based on where the focus is, select a portion of the string(I only have the switch statement options for the month portion, but if it worked I would do the same for day and year). This may be the wrong way to go about it.
Things to note:
By select I mean highlight.
I do not want to use plugins.
This code will select the portion of the date that is clicked on:
$(".date-container").click(function() {
var val = $(this).val();
var sel = this.selectionStart;
var firstSep = val.indexOf("/"), secondSep;
if (firstSep != -1) {
secondSep = val.indexOf("/", firstSep + 1);
if (secondSep != -1) {
if (sel < firstSep) {
this.setSelectionRange(0, firstSep);
} else if (sel < secondSep) {
this.setSelectionRange(firstSep + 1, secondSep);
} else {
this.setSelectionRange(secondSep + 1, val.length);
}
}
}
});​
You can see it work here: http://jsfiddle.net/jfriend00/QV4VT/

Categories