Ответ 1
Кажется, это ошибка, но добавление этой строки в объявлении datepicker должно решить ее:
onSelect: function() {}
У меня есть веб-форма с полем даты начала. Я привязал jquery datepicker к полю txt. Теперь, когда я выбираю дату в FF, выбранная дата заполняется в текстовом поле, и всплывающее окно календаря закрывается. Однако, когда я делаю то же самое в IE8, выбранная дата заполняется в текстовом поле, но всплывающее окно остается открытым. Я также заметил, что ошибка script возникает, как только я выбираю дату во всплывающем календаре.
Я использую 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>
Здесь ошибка script, которую я получаю в IE, когда я выбираю дату:
'length' является нулевым или не является объектом
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();
}
Это происходит на .length в цикле for в конце. Vals имеет значение null и не найден в предыдущем if/else. Я прошел через javascript, и если (typeof (targControl.Validators)!= "undefined" ) возвращает false, а затем if (targControl.tagName.toLowerCase() == "label" ) также возвращает false. Таким образом, длина равна null или не является объектной ошибкой.
Теперь я не уверен, что всплывающее окно datepicker, не закрывающееся в IE, и ошибка script в файле WebResources.axd связаны с ошибками, но я склоняюсь таким образом. Может ли кто-нибудь сказать мне, почему всплывающее окно не закрывается?
Кажется, это ошибка, но добавление этой строки в объявлении datepicker должно решить ее:
onSelect: function() {}
При выборе даты датапикер запускает событие изменения в элементе INPUT
, но проверщик ASP.Net вместо этого выбирает событие click с элементом A
и пытается найти валидаторы на этом элементе A
вместо INPUT
. Это можно наблюдать, проверяя event.srcElement
внутри функции валидатора ValidatorOnChange
. В браузерах, отличных от IE, event.type является "change", а event.target - правильно INPUT
.
В то время как функция no-op onSelect: function() { }
предотвращает ошибку, переопределяя встроенный .change()
параметр datepicker по умолчанию onSelect
, он также предотвращает запуск валидаторов. Здесь обход для обоих:
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); });
это приведет к срабатыванию события validatorchanged с правильными аргументами событий (поле ввода).
Корневая ошибка (я думаю, что это, вероятно, означает функцию или, может быть, обходной путь для известной ошибки 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
для входа как эквивалент
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.
Он был задан до, и решение переопределяет функцию onSelect
с помощью функции no-op.
Это не единственный вид проверки валидатора. Здесь смутно подобная проблема с функцией автозаполнения.
Исправить...
onВыберите: function() {}
.. не работает, если проблема связана с CustomValidator, который полагается на обработчик события sidewr для проверки ввода.
Здесь есть несколько других исправлений...
http://dev.jqueryui.com/ticket/4071
Проблема связана с обработкой событий IE, отличной от других браузеров, и код проверки на стороне клиента, предоставляемый ASP Net, не реагирует изящно на ситуацию, не предусмотренную его авторами.
Это эндемическая проблема с jQuery datepickers и контролью проверки ASP. Как вы говорите, неправильный элемент перекрестно запускает подпрограмму проверки подлинности ASP NET, а затем код M $вызывает ошибку, поскольку элемент запуска в подпрограмме undefined.
Я решил это иначе, чем кто-либо другой, который я видел, решив, что M $должен написать свой код более надежно и, следовательно, обновить часть кода проверки M $, чтобы справиться с элементом undefined. Все остальное, что я видел, по сути, является обходным путем на стороне jQuery и устраняет возможные функциональные возможности (например, с помощью события click вместо изменения).
Бит, который терпит неудачу,
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
который выдает ошибку, когда пытается получить длину для undefined 'vals'.
Я только что добавил
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
и ей хорошо идти. Окончательный код, который переопределяет всю функцию нарушения, приведен ниже. Я помещал его как script в внизу моей главной страницы или страницы (так что это происходит после объявлений по умолчанию и заменяет более раннюю версию).
Да, это нарушает совместимость, если 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();
}
изменить строку jquery.ui.datepicker.js 1504
'" href="#" >' + printDate.getDate() + '</a>')
с
'" href="javascript:DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);" >' + printDate.getDate() + '</a>')
работает тест OK!
Я действительно не знаю, в чем проблема, но я заметил, что у вас нет набора ValidationGroup, и оба ваших валидатора имеют это значение. Вы можете попробовать установить ValidationGroup = "sh" в свой TextBox и посмотреть, помогает ли это.
Основываясь на вышеприведенных ответах и более подробно изложив мои комментарии выше,
Очевидно, что в IE9 + и других браузерах вы должны использовать dispatchEvent
для запуска события изменения. (Почему .fireEvent() не работает в IE9?)
Функция OnSelect
в datepicker фактически имеет 2 аргумента:
Объект с свойством id, который соответствует содержимому текстового поля
mytextbox.datepicker({
defaultDate: null,
numberOfMonths: 1,
dateFormat: DisplayDateFormat,
onSelect: function (value, source) {
}
});
Все примеры, которые я видел, использовали document.getElementById()
для извлечения текстового поля, которое, как я думал, не понадобилось бы, поскольку исходный объект имеет тот же идентификатор, что и текстовое поле. При ближайшем рассмотрении выясняется, что источником является объект, а не элемент текстового поля. Я обнаружил, что следующий код разрешил проблему:
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();
}
}
});
Обновление. Похоже, что этот подход больше не работает - не уверен, почему. Он останавливает ошибку, которую вы бросаете, но не вызывает событие изменения.