[JavaScript] ASP.NET 的 ImageButton 搭配 jQuery validate submitHandler 事件 submit 時在 IE 無法引發伺服器端事件的問題與解法

Standard

前陣子案子遇到的問題,是一個簡單的表單需求,使用 ASP.NET 作為伺服器端語言,而前端要使用 jQuery validate 做驗證再送出。
在送出前需要再做一些事件,所以使用 jQuery validate submitHandler 事件處理,最後再以 form.submit(); 送出。

code 簡單重現如下:

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js"></script>
  <script type="text/javascript">
  $(document).ready(function() {

    $("form").validate({
      onfocusout: false,
      onclick: false,
      onkeyup: false,
      rules: {‘
        txt’: {
          required: true,
          maxlength: 5
        }
      },
      messages: {‘
        txt’: {
          required: "請輸入姓",
          maxlength: "姓請勿大於 5 個字元"
        }
      },
      showErrors: function(errorMap, errorList) {
        var msg = "";
        $.each(errorList, function(i, v) {
          msg += ("‧" + v.message + "\r\n");
        });
        if (msg != "") alert(msg);
      },
      submitHandler: function(form) {
        alert("做些事..開視窗之類的");
        // jQuery 的 submit 會引發無窮迴圈,別用
        //$("form").submit();
        //
        // jQuery validate 中會呼叫 JavaScript 原生的 submit()
        form.submit();
        //
        // 原生的 submit
        //document.getElementById("form1").submit();
      }
    });
  });
  </script>
</head>
<body>
  <form id="form1" runat="server">
    <div>
      <asp:TextBox ID="txt" runat="server"></asp:TextBox>
      <asp:ImageButton ID="ImageButton1" runat="server" onclick="ImageButton1_Click" />
    </div>
  </form>
</body>
</html>

還有 Code Behind 的部分,是 ImageButton1 的點擊事件:

protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
  Response.Write("我是 ImageButton1 按下後引發的事件");
}

其中 submitHandler 事件:

submitHandler: function (form) {
  alert('做些事..開視窗之類的');
  form.submit();
}

做表單的送出前的事件處理,記得不要用 $("#form1").submit(); 送出,
不然會引發無窮迴圈,一直在送出 -> 驗證 -> 送出 -> 驗證中鬼打牆,以本例來說的話就會不斷地跳 alert。
請用 form.submit(); 來觸發表單送出事件,這是 jQuery validate 中呼叫 JavaScript 原生的 submit。

好了,解決了無窮迴圈的問題,但接下來我發現上面這段 Code 在 Chrome 雖一切正常,但在 IE 中就是無法引發 ImageButton1_Click 的伺服器端事件,
但確實有被 submit,畫面閃了一下。所以應該是 IE 少送了什麼東西,導致 ASP.NET 不知道是哪個控制項引發表單送出的囉?

先來一段純 HTML 來做實驗:

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js"></script>
  <script type="text/javascript">
  $(document).ready(function() {

    $("form").validate({
      onfocusout: false,
      onclick: false,
      onkeyup: false,
      rules: {‘
        txt’: {
          required: true,
          maxlength: 5
        }
      },
      messages: {‘
        txt’: {
          required: "請輸入姓",
          maxlength: "姓請勿大於 5 個字元"
        }
      },
      showErrors: function(errorMap, errorList) {
        var msg = "";
        $.each(errorList, function(i, v) {
          msg += ("‧" + v.message + "\r\n");
        });
        if (msg != "") alert(msg);
      },
      submitHandler: function(form) {
        alert("做些事..開視窗之類的");
        // jQuery 的 submit 會引發無窮迴圈,別用
        //$("form").submit();
        //
        // jQuery validate 中會呼叫 JavaScript 原生的 submit()
        form.submit();
        //
        // 原生的 submit
        //document.getElementById("form1").submit();
      }
    });
  });
  </script>
</head>
<form id="form1" action="" method="get">
  <input type="text" name="txt" value="test" />
  <input type="image" src="圖檔位置" />
</form>

如果用上面這段 code 去觀察的話,應該可以發現 Chrome 跟 IE 的差別,Chrome 在送出時除了 txt 的值還會附加 x 跟 y 的值,而 IE 只會有 txt 的值。
IE 只有在真的「點擊」那顆 image button 造成 submit 事件時,才會附加 x 跟 y。(如果用 ASP.NET 去做的話,就會找不到 Request.Form[“ImageButton1.x”])
上面那段 code 最後是透過 javascript 去送出表單的,而非真的點擊該 image button,因此就不會有 x 跟 y 的值了。

 

依照 ASP.NET PostBack 的運作機制,除了用 __doPostBack 搭配 __EVENTTARGET 判斷外,
也會判斷控制項類型 Button 或 ImageButton,若為 ImageButton 的話,還會在控制項名稱後面附加 .x 跟 .y,像是這樣:ImageButton1.x。
上述都是用以判斷是哪個控制項,接下來要引發哪一段 PostBack 的事件。

 

看來就是因為在上面情況中,IE 不會送出 ImageButton 的 x 跟 y 值導致 ImageButton1 的 Click 事件沒有被引發了。

解決方法也不難,可以這樣做:

 

如果去檢視 ASP.NET render 的 HTML,可以找到:

var theForm = document.forms[‘form1’];

if (!theForm) {
  theForm = document.form1;
}


function __doPostBack(eventTarget, eventArgument) {
  if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
    theForm.__EVENTTARGET.value = eventTarget;
    theForm.__EVENTARGUMENT.value = eventArgument;
    theForm.submit();
  }
}

我們可以利用 __doPostBack 來解決,因為它做的事情就是將控制項名稱放入 __EVENTTARGET 的值再送出。
將 submitHandler 事件改為:

submitHandler: function (form) {
  alert('做些事..開視窗之類的');
  __doPostBack('<%=控制項名稱.ClientID %>', '');
}

或是乾脆直接塞值給 __EVENTTARGET

submitHandler: function (form) {
  alert('做些事..開視窗之類的');
  form.__EVENTTARGET.value = '<%= ImageButton1.ClientID %>';
  form.submit();
}

 

 

以上分享。
如果有更不錯的解法,或是觀念不大正確的地方,請不吝給予指導,感謝 : )

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *