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

Standard

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

 

code 簡單重現如下:

[code language=”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>
<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]

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

[code language=”csharp”]
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
Response.Write("我是 ImageButton1 按下後引發的事件");
}
[/code]

其中 submitHandler 事件:

[code language=”javascript”]
submitHandler: function (form) {
alert("做些事..開視窗之類的");
form.submit();
}
[/code]

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

 

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

 

先來一段純 HTML 來做實驗:

[code language=”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]

如果用上面這段 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,可以找到:

[code language=”javascript”]
//<![CDATA[
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();
}
}
//]]>
[/code]

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

[code language=”javascript”]
submitHandler: function (form) {
alert("做些事..開視窗之類的");
__doPostBack("<%=控制項名稱.ClientID %>", "");
}
[/code]

或是乾脆直接塞值給 __EVENTTARGET:

[code language=”javascript”]
submitHandler: function (form) {
alert("做些事..開視窗之類的");
form.__EVENTTARGET.value = "<%= ImageButton1.ClientID %>";
form.submit();
}
[/code]

 

 

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

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *