在IE8中的选择日期,Jquery datepicker弹出窗口没有关闭

我有一个带有开始日期字段的Web表单。 我已将jquery datepicker绑定到txt字段。 现在,当我在FF中选择日期时,将在文本框中填充所选日期,并关闭日历弹出窗口。 但是,当我在IE8中执行相同操作时,所选日期将填充在文本框中,但弹出窗口仍保持打开状态。 我还注意到,一旦在弹出日历中选择日期,就会生成脚本错误。

我正在使用jquery 1.3.2,jquery-ui 1.7.2和.NET 3.5。 这是我的代码示例:

 $(document).ready(function() { $("#").datepicker({ changeMonth: true, changeYear: true, showButtonPanel: true, showOn: 'button', buttonImage: '/_layouts/images/CALENDAR.GIF', buttonImageOnly: true }); });  
Start Date:
ex. MM/DD/YYYY

这是我选择日期时在IE中遇到的脚本错误:

‘length’为null或不是对象

WebResource.axd的

这是抛出错误的代码:

 function ValidatorOnChange(event) { if (!event) { event = window.event; } Page_InvalidControlToBeFocused = null; var targetedControl; if ((typeof(event.srcElement) != "undefined") && (event.srcElement != null)) { targetedControl = event.srcElement; } else { targetedControl = event.target; } var vals; if (typeof(targetedControl.Validators) != "undefined") { vals = targetedControl.Validators; } else { if (targetedControl.tagName.toLowerCase() == "label") { targetedControl = document.getElementById(targetedControl.htmlFor); vals = targetedControl.Validators; } } var i; for (i = 0; i < vals.length; i++) { ValidatorValidate(vals[i], null, event); } ValidatorUpdateIsValid(); } 

它发生在最后的for循环中的.length上。 Vals为null,在之前的if / else中找不到。 我已经逐步完成了javascript和if(typeof(targetedControl.Validators)!=“undefined”)返回false,然后if(targetedControl.tagName.toLowerCase()==“label”)也返回false。 因此长度为null或不是对象错误。

现在我不确定日期选择器弹出窗口是否在IE中没有关闭,而且WebResources.axd文件中的脚本错误是否是相关错误,但我是这样倾向的。 谁能告诉我为什么弹出窗口没有关闭?

它似乎是一种错误,但在datepicker声明中添加这一行应解决它:

 onSelect: function() {} 

选择日期时,datepicker会触发INPUT元素上的change事件,但ASP.Netvalidation器会选择click事件,源代码为A元素,并尝试在该A元素上查找validation器,而不是INPUT 。 通过检查validation器的ValidatorOnChange函数中的event.srcElement可以观察到这一点。 在IE以外的浏览器中,event.type为’change’,event.target正确为INPUT

虽然no-op函数onSelect: function() { }通过覆盖内置于.change()默认onSelect.change()来防止错误,但它也阻止了validation器的触发。 以下是两者的解决方法:

 onSelect: function() { this.fireEvent && this.fireEvent('onchange') || $(this).change(); } 

这使用正常的.change()触发器,除了在IE上,需要使用.fireEvent来使事件对象与更改而不是单击相关联。

上面提供的解决方案仅防止发生错误。

在datepicker上:

 onSelect : function(dateText, inst){ inst.input.trigger('cValidate') 

并将事件绑定到日历输入元素。

 .bind('cValidate', function (event) { window.ValidatorOnChange(event); }); 

这将使用正确的事件args(输入字段)触发validatorchanged事件。

原因

根错误(我认为它可能是一个function,或者可能是已知的IE错误的解决方法?)在ASP.Net的ValidatorHookupEvent

 var func; if (navigator.appName.toLowerCase().indexOf('explorer') > -1) { func = new Function(functionPrefix + " " + ev); } else { func = new Function("event", functionPrefix + " " + ev); } 

因此,在默认情况下,没有注册其他onchange ,这onchange输入的onchange为等效于

 function() { ValidatorOnChange(event); } 

在IE和

 function(event) { ValidatorOnChange(event); } 

在其他浏览器中。 因此,如果您使用的是IE,则传递给ValidatorOnChange的事件将是window.event (因为window是全局对象)。

建议的解决方案

如果您不想破解ASP.Net脚本,那么我认为处理这个问题最好的方法是检测损坏的事件处理程序并替换它。 与此处的其他建议一样,我提供了onSelect以包含在datepicker选项中。

 onSelect: function(dateStr, datePicker) { // http://stackoverflow.com/questions/1704398 if (datePicker.input[0].onchange.toString().match(/^[^(]+\(\)\s*{\s*ValidatorOnChange\(event\);\s*}\s*$/)) { datePicker.input[0].onchange = ValidatorOnChange; } datePicker.input.trigger("change"); } 

我正在全球范围内应用它

 $.datepicker.setDefaults({ onSelect: function(dateStr, datePicker) { etc. } }); 

由于为您生成了ValidatorOnChange代码,因此您看起来并没有做错任何事情; 它在创建vals对象的方式上出现了问题,这似乎在ie8上最终为null。

以前曾经问过 ,解决方案是使用no-op函数覆盖onSelect函数。

这不是唯一一种validation器问题。 这是一个与自动完成function模糊相似的问题 。

修复……

onSelect:function(){}

..如果问题出在依赖于服务端事件处理程序validation输入的CustomValidator上,则似乎不起作用。

这里提到了几个其他修复…

http://dev.jqueryui.com/ticket/4071

问题在于IE的事件处理与其他浏览器不同,ASP Net提供的客户端validation代码没有对其作者未考虑的情况做出优雅反应。

这是jQuery datepickers和ASPvalidation控件的地方性问题。 正如您所说,错误的元素交叉触发ASP NET javascriptvalidation例程,然后M $代码抛出错误,因为例程中的触发元素未定义。

我通过决定M $应该更强大地编写代码来解决这个问题,并因此重新声明了一些M $validation器代码来处理未定义的元素。 我所看到的其他所有内容基本上都是jQuery方面的解决方法,并且可以削减可能的function(例如,使用click事件而不是更改)。

失败的是

  for (i = 0; i < vals.length; i++) { ValidatorValidate(vals[i], null, event); } 

当它试图获取未定义的'vals'的长度时会抛出错误。

我刚才补充道

 if (vals) { for (i = 0; i < vals.length; i++) { ValidatorValidate(vals[i], null, event); } } 

她很高兴。 重新声明整个违规function的最终代码如下。 我将它作为脚本包含在我的母版页或页面的底部 (因此它发生默认声明之后并替换了早期版本)。

是的,如果M $决定在将来更改其validation器代码,这确实会破坏向上兼容性。 但人们希望他们能解决它,然后我们可以完全摆脱这个补丁。

 // Fix issue with datepicker and ASPNET validators: redeclare MS validator code with fix function ValidatorOnChange(event) { if (!event) { event = window.event; } Page_InvalidControlToBeFocused = null; var targetedControl; if ((typeof (event.srcElement) != "undefined") && (event.srcElement != null)) { targetedControl = event.srcElement; } else { targetedControl = event.target; } var vals; if (typeof (targetedControl.Validators) != "undefined") { vals = targetedControl.Validators; } else { if (targetedControl.tagName.toLowerCase() == "label") { targetedControl = document.getElementById(targetedControl.htmlFor); vals = targetedControl.Validators; } } var i; if (vals) { for (i = 0; i < vals.length; i++) { ValidatorValidate(vals[i], null, event); } } ValidatorUpdateIsValid(); } 

改变jquery.ui.datepicker.js第1504行

 '" href="#" >' + printDate.getDate() + '') 

 '" href="javascript:DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' + inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);" >' + printDate.getDate() + '') 

测试工作正常!

我真的不知道问题是什么,但我注意到你没有设置ValidationGroup,并且你的两个validation器都设置了这个值。 您可以尝试在TextBox中设置ValidationGroup =“sh”,看看是否有帮助。

基于上述答案并提供上述评论的进一步细节,

显然在IE9 +和其他浏览器中,您现在应该使用dispatchEvent来触发change事件。 ( 为什么.fireEvent()在IE9中不起作用? )

OnSelect中的OnSelect函数实际上有2个参数:

  1. 与datepicker关联的文本框的值
  2. 具有与文本框的属性匹配的id属性的对象

     mytextbox.datepicker({ defaultDate: null, numberOfMonths: 1, dateFormat: DisplayDateFormat, onSelect: function (value, source) { } }); 

我看到的所有示例都使用document.getElementById()来检索文本框,我认为不需要看到,因为源对象具有与文本框相同的id。 仔细研究后发现,source是一个对象,而不是textbox元素。 我发现以下代码解决了这个问题:

  mytextbox.datepicker({ defaultDate: null, numberOfMonths: 1, dateFormat: DisplayDateFormat, onSelect: function (value, source) { var ctrl = document.getElementById(source.id); if ("dispatchEvent" in ctrl) { // IE9 var evt = document.createEvent("HTMLEvents"); evt.initEvent("change", false, true); ctrl.dispatchEvent(evt); } else if ("fireEvent" in ctrl) { // IE7/IE8 ctrl.fireEvent("onchange"); } else { $(ctrl).change(); } } }); 

更新:似乎这种方法不再有效 – 不确定原因。 它会停止抛出错误,但不会触发更改事件。