【问题标题】:Weird bug when combining an ASP.NET updatepanel with the jQuery UI DatePicker将 ASP.NET 更新面板与 jQuery UI DatePicker 组合时出现奇怪的错误
【发布时间】:2009-09-10 18:10:45
【问题描述】:

我创建了一个结合了内联 jQuery UI datepicker 的页面。当用户单击新日期以更新某些数据时,我不想启动对更新面板的回调。现在,这个页面有多个更新面板(不要问:)),所以我需要检查哪个更新面板进行了重新加载,以便在客户端做一些事情。我使用__doPostBack 进行回发,使用Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(sender, args) {} 监听更新何时完成。

问题在于,在 FF 中,回调告诉我它不是异步操作,并且我需要检查哪个更新面板进行了更新的数据设置为 null。

我的问题是这在 IE 中可以正常工作,但在任何其他浏览器中都不能,这可能是由 2 件事引起的: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 回调之间的互操作性问题?

我们将不胜感激任何帮助或想法。

谢谢。

[更新] 蒂姆解决了它!非常感谢! - 还要感谢所有花时间试图解决这个问题的人:)

【问题讨论】:

    标签: jquery asp.net ajax quirks-mode


    【解决方案1】:

    我觉得你觉得这篇来自 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 版本中停止使用。

    【讨论】:

      【解决方案2】:

      我已经使用 ScriptManager 上的 ScriptMode="Release" 参数修复了 jQuery/Updatepanels 的各种异步问题。

        <asp:ScriptManager ID="scriptManager" runat="server" ScriptMode="Release">
        </asp:ScriptManager>
      

      【讨论】:

        【解决方案3】:

        AJAX 和 jQuery 组合的一个常见问题是这个...

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

        仅在第一个页面加载时发生。如果替换了已经被 buildDatapicker() 影响的 HTML 区域;您丢失了任何附加到它的事件(即使您已将其替换为相同的元素)。

        您需要做的就是针对新加载的 HTML 调用 buildDatepicker...并传入已加载的元素以确保您不会重复...

        $(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);重新绑定数据选择器功能。

        【讨论】:

        • 好吧,日期选择器已经在更新面板的内容范围之外,所以它不应该受到影响。我尝试了您的解决方案,但它仍然在 firefox 中显示 null :(
        【解决方案4】:

        您可以尝试使用 datepicker 设置一个 altField 并检查更改以进行回发。

        【讨论】:

        • 是的,似乎这是唯一的出路:(
        【解决方案5】:

        我已尝试使用您的代码重现该错误,并且可以重现该错误。我得出的结论是 jQuery/UpdatePanels 存在一些问题。

        如果我用 LinkBut​​ton 替换按钮,您可以看到该链接直接调用 __doPostBack(...),与您调用的参数完全相同的函数。并且直接点击链接按钮有效,但点击日期无效。

        这意味着 jQuery 内部发生了一些改变某些上下文的事情。但我不知道那会是什么。

        【讨论】:

          【解决方案6】:

          不久前我发现了另一个脚本,我已经使用了一段时间并且从未遇到任何问题。

           <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>
          

          您仍然可以像在上面的脚本中一样手动设置回调函数。

          您可能还必须手动添加脚本资源处理程序(不记得是哪个),但我特别记得在调用异步和非异步回发时遇到问题。希望对您有所帮助。

          【讨论】:

            【解决方案7】:

            看起来像一个竞争条件,试试 UpdateMode="Conditional" 和 ChildrenAsTriggers="false",reference

            【讨论】:

            • 没有帮助,虽然我同意它看起来像一个竞争条件:)
            【解决方案8】:

            但是,如果我单步执行 FireBug 足够慢,它可以工作

            哦?为什么不给它一秒钟的时间来解决它?

            setTimeout(function(){alert(sender._postBackSettings.panelID);},1000);
            

            【讨论】:

            • 呵呵.. 是的,试过了,但这不是我正在寻找的那种解决方案 xD
            【解决方案9】:

            我喜欢 Tim 的回答,围绕着您应该在 pageLoaded 事件中使用 args.get_PanelsUpdated() 的想法。这似乎是做你想做的事情的合适方法。试试看 - 如果它不起作用,那么我还有另一个想法(虽然它有点脏)。

            【讨论】:

              【解决方案10】:

              我觉得这很有趣,如果你在 doPostBack 之后添加一个警报,那么 FF 不会返回 null。

                  function doAspNetPostback() {
              
                      __doPostBack('<%= hiddenOnSelectionChangedButton.ClientID %>', '');
                      alert('<%= hiddenOnSelectionChangedButton.ClientID %>');
                  }
              

              【讨论】:

                猜你喜欢
                • 2011-01-25
                • 2015-04-21
                • 2015-06-08
                • 1970-01-01
                • 1970-01-01
                • 2017-05-21
                • 2017-09-22
                • 1970-01-01
                • 2013-12-31
                相关资源
                最近更新 更多