以jQuery AJAX方式在表單送出前進行資料檢核
2 |
今天同事剛好問到如何透過AJAX方式在表單送出前進行資料檢核,索性把我的做法整理一下,供大家參考指教。
先用一個非AJAX,純Javascript的範例開始說明。
假設有一個ASP.NET網頁,txtCode輸入文字,btnSubmit送出表單,用jQuery在btnSubmit掛上onClick事件,檢查txtCode是否為"Darkthread": 若否就alert("Invalid!");若是則return true允許送出表單。程式很單簡單,在此就不再多做說明,請大家自行參考以下程式碼: (txtCode前方我放了一個Plurk跳舞香蕉人當伏筆)
<%@ Page Language="C#" %>
<script runat="server">
protected void btnSubmit_Click(object sender, EventArgs e)
{
Response.Write(txtCode.Text);
Response.End();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Async Call</title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.4.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
function validate() {
if ($("#txtCode").val() == "Darkthread")
return true;
else
return false;
}
$("#btnSubmit").click(function () {
if (!validate()) {
alert("Invalid!");
return false;
}
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<img src="http://statics.plurk.com/a55bdb344892676b0fea545354654a49.gif" />
<asp:TextBox ID="txtCode" runat="server"></asp:TextBox>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</form>
</body>
</html>
下一步,假設檢查邏輯很複雜,涉及資料庫查詢,故只能在Server端進行。我們將其修改為AJAX版,在Page_Load中加入邏輯,以Request["m"] == "validate"為觸發條件,透過Request["t"]取得使用者輸入文字,依文字是否為"Darkthread"決定傳回"OK"或"FAIL"。
再來看前端的Script要怎麼寫,首先示範懶人寫法:
由於btnSubmit在click事件需等待AJAX呼叫結果才能決定return true或false,所以我們做點小手腳,捨棄$.get()或$.post()不用,改用$.ajax(),借用其中一個參數: async,很沒出息地把它設成false(預設為true,$.get()/$.post()時也都被設為true)... 這樣有個好處: $.ajax()執行時,程式會卡住直到AJAX呼叫的結果傳回為止,程式邏輯可以一氣喝成,跟先前寫法一樣單純:
<%@ Page Language="C#" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (Request["m"] == "validate")
{
//System.Threading.Thread.Sleep(5000);
Response.Write(Request["t"] == "Darkthread" ? "OK" : "FAIL");
Response.End();
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
Response.Write(txtCode.Text);
Response.End();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Async Call</title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.4.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
function validate() {
var res = "";
$.ajax({
url: "Test.aspx",
data: { m: "validate", t: $("#txtCode").val() },
success: function (result) { res = result; },
cache: false,
async: false
});
return res == "OK";
}
$("#btnSubmit").click(function () {
if (!validate()) {
alert("Invalid!");
return false;
}
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<img src="http://statics.plurk.com/a55bdb344892676b0fea545354654a49.gif" />
<asp:TextBox ID="txtCode" runat="server"></asp:TextBox>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</form>
</body>
</html>
這個做法之所以沒出息,是因為同步式呼叫(async: false)將會中斷網頁執行,等待結果的過程中,網頁將被凍結。試著將Page_Load裡Thread.Sleep(5000)的註解拿掉,就可以借香蕉人突顯這個弱點。在等待的五秒裡,香蕉人僵住定格,不再跳舞,整個網頁也對使用者的滑鼠、鍵盤毫無反應。基本上,這不是良好的介面設計模式,更何況,AJAX的A意指Asynchronous(非同步),搞到網頁卡卡,恐有山寨AJAX之嫌。
是男人就要走非同步,是好漢就不該讓網頁卡住!
以下示範更友善的AJAX檢查寫法。首先,我們增設一個ajaxValidPass變數以標示是否通過檢核。按下btnSubmit時,先檢查ajaxValidPass是否已標為通過,若是則放行進行PostBack;若否,則將按鈕及輸入框設為disabled,並顯示"檢核中..."的訊息,再以$.get()或$.post()方式呼叫Server端檢查。在success函數中,先解除按鈕及輸入框的disabled,消除"檢核中..."字樣,並由傳回結果決定要顯示alert("Invalid!"),或是設定ajaxValidPass=true並自動呼叫$("#btnSubmit").click(),在這個程式觸發的click事件裡,由於ajaxValidPass已設為true,故會略過觸發AJAX檢核的邏輯,送出表單。
<%@ Page Language="C#" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
if (Request["m"] == "validate")
{
System.Threading.Thread.Sleep(5000);
Response.Write(Request["t"] == "Darkthread" ? "OK" : "FAIL");
Response.End();
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
Response.Write(txtCode.Text);
Response.End();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Async Call</title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.4.4.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
function validate() {
$.get("Test.aspx",
{ m: "validate", t: $("#txtCode").val(), r: Math.random() },
function (result) {
window.ajaxValidPass = (result == "OK");
//恢復按鈕及輸入框
$(".clsInput").removeAttr("disabled");
//清除檢核中...顯示字樣
$("#spnDisp").text("");
//檢核未過發出提示
if (!window.ajaxValidPass)
alert("Invalid!");
else //檢核若完成,自動按送出鈕送出表單
$("#btnSubmit").click();
});
}
$("#btnSubmit").click(function () {
//若未經過AJAX檢核,觸發動作
if (!window.ajaxValidPass) {
//停用按鈕及輸入框
$(".clsInput").attr("disabled", true);
//顯示檢核中
$("#spnDisp").text("檢核中...");
//開始AJAX檢核
validate();
//先傳回false,暫時不送出表單
return false;
}
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<img src="http://statics.plurk.com/a55bdb344892676b0fea545354654a49.gif" />
<asp:TextBox ID="txtCode" runat="server" CssClass="clsInput"></asp:TextBox>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" CssClass="clsInput"
onclick="btnSubmit_Click" />
<span id="spnDisp"></span>
</form>
</body>
</html>
實際測試可驗證,等待期間香蕉人還是跳個不停、嗨到不行,網頁其他部分也反應如常,操作介面更加人性化囉!
後記: 以上程式碼以示範原理為主,故力求簡單、避免失焦。實務應用上,"檢核中..."字樣可用更精緻的圖文表示、停用按鈕與輸入框的可考慮改採BlockUI()。至於Client端的檢核,多半只能視為正式送出內容前的迅捷預覽,減少將無效資料傳至後端的無謂往返傳輸,千萬不可當成資料有效性的唯一檢核關卡,務必要在Server端重新檢核一次,以免因Script停用、故障或被破解等因素影響資料有效性,甚至危害資安。
【延伸閱讀】
Comments
# by 阿尼
好!果然是鐵錚錚的好漢
# by jain
好用~~趕快記下來~~~