Jquery datepicker 弹出窗口未在 IE8 中的选择日期关闭
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1704398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Jquery datepicker popup not closing on select date in IE8
提问by Notorious2tall
I've got a web form with a start date field. I've tied a jquery datepicker to the txt field. Now when I choose a date in FF, the selected date is populated in the text box and the calendar popup closes. However when I do the same thing in IE8, the selected date is populated in the text box but the popup remains open. I've also noticed that a script error is generated as soon as I select a date in the popup calendar.
我有一个带有开始日期字段的网络表单。我已将 jquery datepicker 绑定到 txt 字段。现在,当我在 FF 中选择一个日期时,所选日期将填充在文本框中并且日历弹出窗口关闭。但是,当我在 IE8 中做同样的事情时,所选日期填充在文本框中,但弹出窗口保持打开状态。我还注意到,一旦我在弹出日历中选择了一个日期,就会生成一个脚本错误。
I'm using jquery 1.3.2, jquery-ui 1.7.2, and .NET 3.5. Here's an example of my code:
我正在使用 jquery 1.3.2、jquery-ui 1.7.2 和 .NET 3.5。这是我的代码示例:
<script type="text/javascript">
$(document).ready(function() {
$("#<%=txtStartDate.ClientID%>").datepicker({
changeMonth: true,
changeYear: true,
showButtonPanel: true,
showOn: 'button',
buttonImage: '/_layouts/images/CALENDAR.GIF',
buttonImageOnly: true
});
});
</script>
<div id="stylized">
<asp:ValidationSummary ID="vs" runat="server" CssClass="messages-error" HeaderText=" Action required before the form can be submitted." ForeColor="" ValidationGroup="sh" />
<div class="formrow">
<div class="ms-formlabel formlabel">
<asp:Label ID="lblStartDate" runat="server" CssClass="ms-standardheader" AssociatedControlID="txtStartDate">Start Date:</asp:Label>
</div>
<div class="ms-formbody formfield">
<asp:RequiredFieldValidator ID="reqStartDate" runat="server" ControlToValidate="txtStartDate" ErrorMessage="Start Date is a required field." Text="*" Display="Dynamic" ValidationGroup="sh"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="cvStartDate" runat="server" ControlToValidate="txtStartDate" ErrorMessage="Date must be in the format MM/DD/YYYY" Text="*" Display="Dynamic" ValidationGroup="sh" Operator="DataTypeCheck" Type="Date"></asp:CompareValidator>
<asp:TextBox ID="txtStartDate" runat="server"></asp:TextBox>
<span class="formMessage">ex. MM/DD/YYYY</span>
</div>
</div>
<div id="buttonrow">
<asp:Button ID="btnSubmit" runat="server" Text="Submit" CssClass="ms-ButtonHeightWidth" OnClick="Submit_Click" ValidationGroup="sh" />
<asp:Button ID="btnCancel" runat="server" Text="Cancel" CssClass="ms-ButtonHeightWidth" OnClick="Cancel_Click" CausesValidation="false" />
</div>
</div>
Here's the script error I get in IE when I select the date:
这是我在 IE 中选择日期时遇到的脚本错误:
'length' is null or not an object
'length' 为 null 或不是对象
WebResource.axd
网络资源文件
Here's the code where the error is being thrown from:
这是从中抛出错误的代码:
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();
}
It happens on the .length in the for loop at the end. Vals is null and isn't found in the previous if/else. I've stepped through the javascript and if (typeof(targetedControl.Validators) != "undefined") returns false and then if (targetedControl.tagName.toLowerCase() == "label") returns false too. Thus the length is null or not an object error.
它发生在最后的 for 循环中的 .length 上。Vals 为空并且在之前的 if/else 中找不到。我已经逐步完成了 javascript 并且 if (typeof(targetedControl.Validators) != "undefined") 返回 false ,然后 if (targetedControl.tagName.toLowerCase() == "label") 也返回 false 。因此长度为空或不是对象错误。
Now I'm not sure if the datepicker popup not closing in IE and the script error in the WebResources.axd file are related errors, but I'm leaning that way. Can anyone tell me why the popup isn't closing?
现在我不确定日期选择器弹出窗口是否未在 IE 中关闭以及 WebResources.axd 文件中的脚本错误是否是相关错误,但我倾向于这种方式。谁能告诉我为什么弹出窗口没有关闭?
采纳答案by Marek Karbarz
It seems to be a bug of sorts, but adding this line in the datepicker declaration should solve it:
这似乎是一个错误,但在 datepicker 声明中添加这一行应该可以解决它:
onSelect: function() {}
回答by rdworth
As a date is selected, the datepicker triggers the change event on the INPUT
element, but the ASP.Net validator picks up the click event instead, with the source an A
element, and tries to find the validators on that A
element, instead of the INPUT
. This can be observed by inspecting event.srcElement
inside the validator's ValidatorOnChange
function. In browsers other than IE, event.type is 'change' and event.target is correctly the INPUT
.
选择日期后,日期选择器会触发INPUT
元素上的更改事件,但 ASP.Net 验证器改为选择单击事件,源是一个A
元素,并尝试在该A
元素上查找验证器,而不是INPUT
. 这可以通过检查event.srcElement
验证器的ValidatorOnChange
函数内部来观察。在 IE 以外的浏览器中, event.type 是 'change' 而 event.target 正确地是INPUT
.
While the no-op function onSelect: function() { }
prevents the error, by overriding the .change()
built-in to the datepicker's default onSelect
, it also prevents the validators from triggering. Here's a work-around for both:
虽然 no-op 函数onSelect: function() { }
通过覆盖.change()
内置到 datepicker 的 default 来防止错误onSelect
,它还可以防止验证器触发。这是两者的解决方法:
onSelect: function() {
this.fireEvent && this.fireEvent('onchange') || $(this).change();
}
This uses the normal .change()
trigger except on IE, where it's required to use .fireEvent
to get the event object to be associated with the change and not the click.
这使用普通.change()
触发器,IE 除外,在 IE 上需要使用它.fireEvent
来获取与更改而不是单击相关联的事件对象。
回答by Vexanthrope
The solutions provided above only prevents the error from occurring.
上面提供的解决方案只能防止错误发生。
On the datepicker:
在日期选择器上:
onSelect : function(dateText, inst){ inst.input.trigger('cValidate')
and bind the event to the calendar input element.
并将事件绑定到日历输入元素。
.bind('cValidate', function (event) { window.ValidatorOnChange(event); });
this will fire the validatorchanged event with the correct event args (input field).
这将使用正确的事件参数(输入字段)触发 validatorchanged 事件。
回答by Peter Taylor
The reason
原因
The root bug (I think it's probably meant to be a feature, or maybe a workaround for a known IE bug?) is in ASP.Net's ValidatorHookupEvent
:
根本错误(我认为它可能是一个功能,或者可能是已知 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);
}
As a result, in the default case that there's no other onchange
registered, this sets up the onchange
for the input to be the equivalent of
结果,在没有其他onchange
注册的默认情况下,这将onchange
输入设置为等效于
function() { ValidatorOnChange(event); }
in IE and
在 IE 和
function(event) { ValidatorOnChange(event); }
in other browsers. So iff you're using IE, the event passed to ValidatorOnChange
will be window.event
(since window
is the global object).
在其他浏览器中。因此,如果您使用的是 IE,则传递给的事件ValidatorOnChange
将是window.event
(因为window
是全局对象)。
A suggested solution
建议的解决方案
If you don't want to hack around with the ASP.Net scripts then I think the nicest way to handle this is to detect the broken event handler and replace it. As with other suggestions here, I offer an onSelect
to include in the datepicker
options.
如果您不想修改 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");
}
I'm applying this globally with
我正在全球范围内应用它
$.datepicker.setDefaults({
onSelect: function(dateStr, datePicker) {
etc.
}
});
回答by Ben McIntyre
This is an endemic problem with jQuery datepickers and ASP validation controls. As you are saying, the wrong element cross-triggers an ASP NET javascript validation routine, and then the M$ code throws an error because the triggering element in the routine is undefined.
这是 jQuery 日期选择器和 ASP 验证控件的普遍问题。正如您所说,错误的元素交叉触发 ASP NET javascript 验证例程,然后 M$ 代码抛出错误,因为例程中的触发元素未定义。
I solved this one differently from anyone else I have seen - by deciding that M$ should have written their code more robustly, and hence redeclaring some of the M$ validator code to cope with the undefined element. Everything else I have seen is essentially a workaround on the jQuery side, and cuts possible functionality out (eg. using the click event instead of change).
我以不同于我见过的任何其他人的方式解决了这个问题 - 通过决定 M$ 应该更健壮地编写他们的代码,因此重新声明一些 M$ 验证器代码来处理未定义的元素。我所看到的其他一切本质上都是 jQuery 方面的一种解决方法,并削减了可能的功能(例如,使用 click 事件而不是更改)。
The bit that fails is
失败的一点是
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
which throws an error when it tries to get a length for the undefined 'vals'.
当它尝试获取未定义的“vals”的长度时会引发错误。
I just added
我刚加
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
and she's good to go. Final code, which redeclares the entire offending function, is below. I put it as a script include at the bottomof my master page or page (so it occurs afterthe default declarations and replaces the earlier version).
她很高兴去。重新声明整个违规函数的最终代码如下。我把它作为一个脚本包含在我的母版页或页面的底部(所以它发生在默认声明之后并替换早期版本)。
Yes, this does break upwards compatibility if M$ decide to change their validator code in the future. But one would hope they'll fix it and then we can get rid of this patch altogether.
是的,如果 M$ 决定将来更改其验证器代码,这确实会破坏向上兼容性。但是人们希望他们能修复它,然后我们就可以完全摆脱这个补丁。
// 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();
}
回答by changcn
change jquery.ui.datepicker.js line 1504
更改 jquery.ui.datepicker.js 第 1504 行
'" href="#" >' + printDate.getDate() + '</a>')
with
和
'" href="javascript:DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);" >' + printDate.getDate() + '</a>')
test works OK!
测试正常!
回答by dlamblin
It doesn't look like you're doing anything wrong since the ValidatorOnChange
code is generated for you; there's something wrong in the way it's creating its vals
object which appears to end up null on ie8.
因为ValidatorOnChange
代码是为您生成的,所以看起来您没有做错任何事情;它创建vals
对象的方式有问题,在 ie8 上似乎最终为 null。
It's been asked before, and the solution is overriding the onSelect
function with a no-op function.
它被要求之前,该溶液是压倒一切的onSelect
功能与无操作功能。
This is not the only kind of validator problem out there. Here's a vaguely similar issuewith the autocomplete feature.
这不是唯一一种验证器问题。这是自动完成功能的一个模糊类似的问题。
回答by Fentex
The fix...
修复...
onSelect: function() {}
onSelect: function() {}
..does not appear to work if the problem is with a CustomValidator that relies on a servewr side event handler to validate input.
..如果问题出在依赖服务器端事件处理程序来验证输入的 CustomValidator 上,则似乎不起作用。
There are a couple of other fixes mentioned here...
这里提到了一些其他修复......
http://dev.jqueryui.com/ticket/4071
http://dev.jqueryui.com/ticket/4071
The problem is down to IE's event handling differing from other browsers and the client side validation code supplied by ASP Net not reacting gracefully to a situation not contemplated by it's authors.
问题归结为 IE 的事件处理与其他浏览器不同,并且 ASP Net 提供的客户端验证代码没有对其作者未考虑的情况做出适当的反应。
回答by KevnRoberts
I don't really know what the problem is, but I did notice that your does not have the ValidationGroup set, and both of your validators have that value set. You might try setting ValidationGroup="sh" in your TextBox and see if that helps.
我真的不知道问题是什么,但我确实注意到您没有设置 ValidationGroup,并且您的两个验证器都设置了该值。您可以尝试在 TextBox 中设置 ValidationGroup="sh" ,看看是否有帮助。
回答by B-K
Building upon the above answers and to provide further detail to my comment above,
在上述答案的基础上,并为我上面的评论提供更多细节,
Apparently in IE9+ and other browsers, you should now use dispatchEvent
to fire the change event. (Why does .fireEvent() not work in IE9?)
显然在 IE9+ 和其他浏览器中,您现在应该使用dispatchEvent
来触发更改事件。(为什么 .fireEvent() 在 IE9 中不起作用?)
The OnSelect
function in the datepicker actually has 2 arguments:
OnSelect
datepicker 中的函数实际上有 2 个参数:
- The value of the textbox associated with the datepicker
An object with an id property that matches that of the textbox
mytextbox.datepicker({ defaultDate: null, numberOfMonths: 1, dateFormat: DisplayDateFormat, onSelect: function (value, source) { } });
- 与日期选择器关联的文本框的值
具有与文本框匹配的 id 属性的对象
mytextbox.datepicker({ defaultDate: null, numberOfMonths: 1, dateFormat: DisplayDateFormat, onSelect: function (value, source) { } });
All the examples I saw used document.getElementById()
to retrieve the textbox, which I thought wouldn't be necessary seeing as the source object has the same id as the textbox. Upon closer examination it turns out that source is an object, not the textbox element. I found the following code resolved the problem though:
我看到的所有示例都用于document.getElementById()
检索文本框,我认为没有必要看到源对象与文本框具有相同的 id。仔细检查后发现 source 是一个对象,而不是文本框元素。我发现以下代码解决了这个问题:
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();
}
}
});
Update: It appears that this approach is no longer working - not sure why. It stops the error from being thrown but doesn't trigger the change event.
更新:似乎这种方法不再有效 - 不知道为什么。它停止抛出错误但不会触发更改事件。