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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 12:00:40  来源:igfitidea点击:

Jquery datepicker popup not closing on select date in IE8

asp.netjqueryjquery-ui

提问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 INPUTelement, but the ASP.Net validator picks up the click event instead, with the source an Aelement, and tries to find the validators on that Aelement, instead of the INPUT. This can be observed by inspecting event.srcElementinside the validator's ValidatorOnChangefunction. 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 .fireEventto 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 onchangeregistered, this sets up the onchangefor 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 ValidatorOnChangewill be window.event(since windowis 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 onSelectto include in the datepickeroptions.

如果您不想修改 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 ValidatorOnChangecode is generated for you; there's something wrong in the way it's creating its valsobject which appears to end up null on ie8.

因为ValidatorOnChange代码是为您生成的,所以看起来您没有做错任何事情;它创建vals对象的方式有问题,在 ie8 上似乎最终为 null。

It's been asked before, and the solution is overriding the onSelectfunction 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 dispatchEventto fire the change event. (Why does .fireEvent() not work in IE9?)

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

The OnSelectfunction in the datepicker actually has 2 arguments:

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

  1. The value of the textbox associated with the datepicker
  2. An object with an id property that matches that of the textbox

    mytextbox.datepicker({
        defaultDate: null,
        numberOfMonths: 1,
        dateFormat: DisplayDateFormat,
        onSelect: function (value, source) {
        }
    });
    
  1. 与日期选择器关联的文本框的值
  2. 具有与文本框匹配的 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.

更新:似乎这种方法不再有效 - 不知道为什么。它停止抛出错误但不会触发更改事件。