Странная ошибка при объединении панели обновления ASP.NET с JQuery UI DatePicker - PullRequest
8 голосов
/ 10 сентября 2009

Я создал страницу, которая объединяет встроенный jQuery UI datepicker . Я не хочу инициировать обратный вызов панели обновления, когда пользователь нажимает новую дату, чтобы обновить некоторые данные. Теперь эта страница имеет несколько панелей обновления (не спрашивайте :)), поэтому мне нужно проверить, какая панель обновлений выполнила перезагрузку, чтобы сделать что-то на стороне клиента. Я использую __doPostBack для обратной передачи и Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(sender, args) {} для прослушивания после завершения обновления.

Проблема в том, что в FF обратный вызов говорит мне, что это не асинхронная операция, и данные, которые мне нужны, чтобы проверить, какая панель обновления выполнила обновление, установлены в нуль.

Моя проблема в том, что это нормально работает в IE, но не в любом другом браузере, что может быть вызвано двумя причинами: IE переходит в причудливый режим, который решает проблему (это то, что я думаю), или что IE имеет какой-то вид встроенной поддержки панели обновления, которую не поддерживают другие браузеры.

Я сузил проблему и создал тестовую страницу:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js "></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js "></script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server" />

    <script type="text/javascript">
        function doAspNetPostback() {
            __doPostBack('<%= hiddenOnSelectionChangedButton.ClientID %>', '');
        }

        $(document).ready(function() {
            /* Create the datepicker */
            buildDatepicker();
            /* Add callback-method for when the scriptmanager finished a request */
            Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(sender, args) {
                /* Show the panelID - This is 'upd1|hiddenOnSelectionChangedButton' in IE as it should be, and null in Chrome / FF */
                alert(sender._postBackSettings.panelID);
            });
        });

        function buildDatepicker() {
            var dp = $("#datepicker").datepicker({
                onSelect: function(dateText, inst) {
                    /* Do a postback when someone clicks a date */
                    doAspNetPostback();
                }
            });
        }        
    </script>

    <div id="datepicker">
    </div>
    <asp:UpdatePanel UpdateMode="Conditional" ID="upd1" runat="server">
        <ContentTemplate>
            <asp:Button ID="hiddenOnSelectionChangedButton" Text="Press me" runat="server" />
            <div id="lala" runat="server">
                Upd1
            </div>
        </ContentTemplate>
    </asp:UpdatePanel>
    </form>
</body>
</html>

Запуск этой тестовой страницы в IE приведет к появлению окна сообщения, которое показывает, что он должен делать, в то время как загрузка его в FF или Chrome приведет к появлению сообщения, в котором будет указано "null":)

Я пробовал все виды вещей, но я не уверен, что может вызвать такое поведение, потому что я не очень глубоко во внутренней работе jQuery или ASP.NET Ajax. Однако, если я перебираю код в FireBug достаточно медленно, он работает ... Что заставляет меня думать, что это может быть проблема с совместимостью между обратными вызовами jQuery и обратными вызовами ASP.NET Ajax?

Любая помощь или идеи будут высоко оценены.

Спасибо.

[ОБНОВЛЕНИЕ] Тим решил это! Большое спасибо! - Также спасибо всем, кто потратил свое время, пытаясь понять это:)

Ответы [ 10 ]

4 голосов
/ 18 сентября 2009

Я думаю, что вы можете найти эту статью из MSDN интересной: http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

В статье говорится, что «Sys.WebForms.PageRequestManager.getInstance (). add_pageLoaded (» также присоединяется к событиям завершения панели обновления.

Он также срабатывает каждый раз, когда запущен асинхронный обратный вызов от имени элемента управления UpdatePanel завершает и содержание внутри этого UpdatePanel обновляется.

тогда в вашем обработчике вы можете просмотреть обновленные панели с помощью

var panels = args.get_panelsUpdated();
for (i=0; i < panels.length; i++) { alert(panels[i]); }

Я бы отказался от использования _ postBackSettings, поскольку "_" означает конфиденциальность и может быть прекращено в будущих версиях asp.net ajax.

1 голос
/ 17 сентября 2009

Я исправил различные асинхронные проблемы с jQuery / Updatepanels, используя аргумент ScriptMode = "Release" в ScriptManager.

  <asp:ScriptManager ID="scriptManager" runat="server" ScriptMode="Release">
  </asp:ScriptManager>
0 голосов
/ 19 сентября 2009

Я подумал, что это было интересно, если вы добавляете предупреждение после doPostBack, тогда FF не возвращает ноль.

    function doAspNetPostback() {

        __doPostBack('<%= hiddenOnSelectionChangedButton.ClientID %>', '');
        alert('<%= hiddenOnSelectionChangedButton.ClientID %>');
    }
0 голосов
/ 18 сентября 2009

Мне понравился ответ Тима, основанный на идее, что вы должны использовать args.get_PanelsUpdated () в событии pageLoaded. Кажется, это подходящее средство для того, что вы пытаетесь сделать. Попробуйте - если это не сработает, тогда у меня в рукаве еще одна идея (хотя она и грязная).

0 голосов
/ 18 сентября 2009

Однако, если я перейду через код в FireBug достаточно медленный, он работает

О? Почему бы не дать ему секунду, чтобы решить это?

setTimeout(function(){alert(sender._postBackSettings.panelID);},1000);
0 голосов
/ 17 сентября 2009

Похоже на состояние гонки, попробуйте UpdateMode = "Conditional" и ChildrenAsTriggers = "false", reference .

0 голосов
/ 17 сентября 2009

Некоторое время назад я нашел другой скрипт, который уже давно использую и с которым у меня никогда не было проблем.

 <script type="text/javascript">
        /*
        [__doPostBackAsync]
        Will send an async postback to the backend
        */
        function __doPostBackAsync(eventName, eventArgs) {
            var prm = Sys.WebForms.PageRequestManager.getInstance();

            //check first if the request queues have this item
            if (!Array.contains(prm._asyncPostBackControlIDs, eventName)) {
                prm._asyncPostBackControlIDs.push(eventName);
            }
            if (!Array.contains(prm._asyncPostBackControlClientIDs, eventName)) {
                prm._asyncPostBackControlClientIDs.push(eventName);
            }
            __doPostBack(eventName, eventArgs);
        }
    </script>

Вы все равно можете вручную установить функцию обратного вызова точно так же, как вы делали это в приведенном выше сценарии.

Возможно, вам также придется вручную добавить обработчик ресурсов сценария (не могу вспомнить, какой именно), но я особенно помню проблемы с вызовом асинхронных и неасинхронных постбэков. Надеюсь, это поможет.

0 голосов
/ 15 сентября 2009

Я попробовал ваш код для воспроизведения ошибки, и я могу воспроизвести ошибку. И я пришел к выводу, что существует некоторая проблема с jQuery / UpdatePanels.

Если я заменю кнопку LinkButton, вы увидите, что ссылка напрямую вызывает __doPostBack (...), точно такую ​​же функцию с точно такими же аргументами, которые вы вызываете. И нажатие кнопки ссылки напрямую работает, но нажатие даты не работает.

Так что это означает, что внутри jQuery происходит что-то, что меняет некоторый контекст. Но я понятия не имею, что это будет.

0 голосов
/ 15 сентября 2009

Вы можете попробовать использовать datepicker для установки altField и проверить, есть ли изменения для обратной передачи.

0 голосов
/ 14 сентября 2009

Общая проблема с комбинациями AJAX и jQuery заключается в том, что это ...

$(document).ready(function() {
       buildDatepicker();

происходит только при первой загрузке страницы. Если вы замените область HTML, на которую повлияла buildDatapicker (); вы потеряли все события, которые были прикреплены к нему (даже если вы заменили его теми же элементами).

Все, что вам нужно сделать, это вызвать buildDatepicker для только что загруженного HTML ... и передать загруженный элемент, просто чтобы убедиться, что вы не удвоите ...

$(document).ready(function() {
       buildDatepicker(document);
...

function buildDatepicker(element) {
    var dp = $("#datepicker", element).datepicker({
        onSelect: function(dateText, inst) {
            /* Do a postback when someone clicks a date */
            doAspNetPostback();
        }
    });
}    

Теперь вы можете вызывать buildDatepicker (myNewlyLoadedElement); перепривязать функциональность средства выбора данных.

...