Подтвердить что ты не робот

Всплывающее окно даты JQuery не закрывается на дату выбора в IE8

У меня есть веб-форма с полем даты начала. Я привязал 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 связаны с ошибками, но я склоняюсь таким образом. Может ли кто-нибудь сказать мне, почему всплывающее окно не закрывается?

4b9b3361

Ответ 1

Кажется, это ошибка, но добавление этой строки в объявлении datepicker должно решить ее:

onSelect: function() {}

Ответ 2

При выборе даты датапикер запускает событие изменения в элементе 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, чтобы связать объект события с изменением, а не щелчком.

Ответ 3

Представленные выше решения только предотвращают возникновение ошибки.

В папке datepicker:

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

и привяжите событие к элементу ввода календаря.

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

это приведет к срабатыванию события validatorchanged с правильными аргументами событий (поле ввода).

Ответ 4

Причина

Корневая ошибка (я думаю, что это, вероятно, означает функцию или, может быть, обходной путь для известной ошибки 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.
    }
});

Ответ 5

Не похоже, что вы делаете что-то неправильно, так как код ValidatorOnChange генерируется для вас; там что-то не так в том, как он создает свой объект vals, который, кажется, заканчивается нулевым значением на ie8.

Он был задан до, и решение переопределяет функцию onSelect с помощью функции no-op.

Это не единственный вид проверки валидатора. Здесь смутно подобная проблема с функцией автозаполнения.

Ответ 6

Исправить...

onВыберите: function() {}

.. не работает, если проблема связана с CustomValidator, который полагается на обработчик события sidewr для проверки ввода.

Здесь есть несколько других исправлений...

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

Проблема связана с обработкой событий IE, отличной от других браузеров, и код проверки на стороне клиента, предоставляемый ASP Net, не реагирует изящно на ситуацию, не предусмотренную его авторами.

Ответ 7

Это эндемическая проблема с 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();
}

Ответ 8

изменить строку 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!

Ответ 9

Я действительно не знаю, в чем проблема, но я заметил, что у вас нет набора ValidationGroup, и оба ваших валидатора имеют это значение. Вы можете попробовать установить ValidationGroup = "sh" в свой TextBox и посмотреть, помогает ли это.

Ответ 10

Основываясь на вышеприведенных ответах и ​​более подробно изложив мои комментарии выше,

Очевидно, что в IE9 + и других браузерах вы должны использовать dispatchEvent для запуска события изменения. (Почему .fireEvent() не работает в IE9?)

Функция OnSelect в datepicker фактически имеет 2 аргумента:

  • Значение текстового поля, связанного с datepicker
  • Объект с свойством 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();
            }
        }
    });

Обновление. Похоже, что этот подход больше не работает - не уверен, почему. Он останавливает ошибку, которую вы бросаете, но не вызывает событие изменения.