问题
The project I am currently working on a project (see my previous question: validate-dynamic-table-rows-on-event-listeners/42408354#42408354) where my table rows are cloned upon successful processing. I have to clear all the inputs, change the nested html objects' classes and ids and everything works fine except the onchangeDate event listener.
I am using jQuery.dataTables to populate my table and the complete: function is where I bind my datepickers to my original input html elements inside my tr tds. Instead of the dp126353729 ids assigned by the datepickers I use the row number for my Ids which is not a problem at all.
My issue is that I use the onchangeDate event to trigger the onfocusout event when I close my datepicker so my table row is processed with the new date. I had to play games by using setTimeout to get the event listeners to pick up the new date in the first place!
The cloned datepicker elements are not triggering onchangeDate. I have tried to bind them to this event without any luck. Using the default ids hasn't helped either.
Here is a JSFIDDLE to show how the cloned datepickers arent triggering onfocusout
Here is my code:
var DatePicker = function(that){
if (jQuery().datepicker) {
alert(that.attr('id'));
that.datepicker({
showOn: "button",
buttonImage: "/images/calendar.png",
buttonImageOnly: true,
buttonText: 'Select a start buying date',
changeMonth: true,
changeYear: true,
beforeShow: function() {
setTimeout(function(){
$('.ui-datepicker').css('z-index', 100100);
}, 0);
},
onSelect: function () {
$('.item-failure').addClass("hidden").hide();
$(this).removeClass("error").tooltip("disable").tooltip("hide");
$('.ui-datepicker').css('z-index', -1);
setTimeout(function(){
//allows date to catchup
},0);
},
onClose: function(){
$(this).trigger("changeDate");
},
minDate: '+1', // The min date that can be selected, i.e. 30 days from the 'now'
maxDate: '+1y' // The max date that can be selected, i.e. + 1 month, 1 week, and 1 days from 'now'
// HR MIN SEC MILLI
//new Date().getTime() + 24 * 60 * 60 * 1000)
}).datepicker();
if($(this).hasClass("newDp")){
$(this).bind("changeDate");
}
}
}
Here you can see the that I trigger the focusout event which in turns does all the row validating and processing:
$(".dp").on("changeDate",function(e){
e.stopImmediatePropagation();
$(this).trigger("focusout");
alert("onchange date" + $(this).val());
});
From there the event that processes the row:
//Iterates thru the entire row when date changed
$(".dp").on("keyup focusout",function (e) {
e.stopImmediatePropagation();
//reset validators
$(".qty").rules('remove','min');
$(".qty").rules('remove','max');
$(".qty").rules('remove','required');
hasQtys = false;
hadOtherQtys = false;
var row = $(this).closest('tr');
$(this).rules('add',{required:true,messages:{required:"Must supply a start buy date."}});
$(this).rules('add',{UsaDate:true,messages:{UsaDate:"Enter date in mm/dd/yyyy format"}});
var buydate = $(this);
var num = 0;
var dow = '';
var delday = '';
var quans = 0;
flag = true;
var qty = $();
var Error = false;
//console.log("dp triggered" + e.type);
//only check date when manually entered.
if(e.type === "keyup" && ($(this).valid() === false || $(this).val() ===""))
{ console.log(e.type + $(this).valid());
$(this).addClass("error").tooltip("enable").show();
$('item-failure').removeClass("hidden").html("You have some errors. See below.").show();
Error = true;
}
//check for qtys in row before processing
row.children("td").each(function(index){
qty = $(this).find(".qty");
//processes the inputs within the row
ProcessRequest(row, qty,dow);
}//eof qty.val undefined
});//eof td children
}//eof error
});//eof event datepicker listener
Here is a screenshot of a datepicker that is created on the complete: function with dataTables which fires from this function succesfully
onClose: function(){
$(this).trigger("changeDate");
},
Here is the cloned datepicker screenshot that does NOT fire on this function:
onClose: function(){
$(this).trigger("changeDate");
},
Here is the code where I clone the datepicker upon processing:
var ProcessRequest = function(tr, count,delday){
var dp = tr.find("[name='BUYDATE']");
//clear all errors
tr.children("td").each(function(){ $(this).find(".qty").removeClass("error").tooltip("disable").tooltip("hide");
});
//insert new row because we create new row off emptyRow
if(tr.find(".itno").hasClass("EmptyRow") && flag == true){
console.log("this was an .EmptyRow");
var $clone = tr.clone();
$clone.insertBefore(tr);
//clear inputs
$clone.children("td").each(function(){
var $input = $(this).find("input");
$input.val("");
});
//destroy datepicker
var dp = $clone.find(".dp");
dp.remove();
//create new DatePicker(dp);
var dpId = $('#table_001 tr').length + 1;
$clone.find("td:eq(13) span").html("<input name='BUYDATE' class='dp newDp form-control-inline' style='width:95px'; />");
dp = $clone.find(".dp");
dp.attr('id',dpId);
DatePicker(dp);
}
Solution: Thanks to armesian I came up with this solution:
var DatePicker = function(that){
if (jQuery().datepicker) {
//alert(that.attr('id'));
that.datepicker({
showOn: "button",
buttonImage: "/images/calendar.png",
buttonImageOnly: true,
buttonText: 'Select a start buying date',
changeMonth: true,
changeYear: true,
beforeShow: function() {
setTimeout(function(){
$('.ui-datepicker').css('z-index', 100100);
}, 0);
},
onSelect: function () {
$('.item-failure').addClass("hidden").hide();
$(this).removeClass("error").tooltip("disable").tooltip("hide");
$('.ui-datepicker').css('z-index', -1);
setTimeout(function(){
//allows date to catchup
},0);
},
onClose: function(){
$(this).trigger("changeDate");
},
minDate: '+1', // The min date that can be selected, i.e. 30 days from the 'now'
maxDate: '+1y' // The max date that can be selected, i.e. + 1 month, 1 week, and 1 days from 'now'
// HR MIN SEC MILLI
//new Date().getTime() + 24 * 60 * 60 * 1000)
}).datepicker();
if($(this).hasClass("newDp")){
$(this).bind("changeDate", function(e) { // this is the missing part in my opinion
e.stopImmediatePropagation();
$(this).trigger("focusout");
alert("onchange date" + $(this).val());
});
//Dynamic binding on cloned datepickers only
$(this).on("focusout",function(){
RowValidation($(this));
});
}
} }
回答1:
For what I could see i'm going to point out a line that I think is where the fix needs to go.
I'm assuming that in this line your intention is to bind the changeDate event to the new created element but the binding is missing the actual function that will get executed when the event is triggered:
// corrected version would be
if($(this).hasClass("newDp")){
$(this).bind("changeDate", function(e) { // this is the missing part in my opinion
e.stopImmediatePropagation();
$(this).trigger("focusout");
alert("onchange date" + $(this).val());
});
}
@yardpenalty you were almost there!. You forget to bind the onfocusout event to the cloned dp. You can add the below line after dp.addClass("newDp"); that should fix it:
dp.on("focusout",function(){
$("<div class='red'></div>").insertBefore("#table_001");
});
Here is working JSFIDDLE
来源:https://stackoverflow.com/questions/42438944/onchangedate-not-triggering-on-cloned-datepicker-objects