謙卑式jQuery檢核: 複合式欄位
0 |
先講一個好消息,不讓ASP.NET MVC專美於前,謙卑式檢核(Unobtrusive Validation)在ASP.NET 4.5 WebForm將成為內建功能囉! 聽到這消息讓我格外振奮,它意味著: 1) 現在已投入的研究心得及開發出來的擴充模組,將來肯定能更廣泛應用,2) 未來寫ASP.NET 4.5 WebForm時,不用額外手工加掛檢核,更加省事 3) 我又押對寶了 ^__^。
這篇要談一個常見問題: 謙卑式檢核的寫法主要透過在特定欄位元素(INPUT、SELECT)加上data-val-* Attributes實現檢核規則設定,直覺上所有檢核都針對該欄位,但在實務上,某些檢核邏輯涉及的欄位元素常不只一個。舉例來說,某個申辦門號註冊網頁,使用者可透過Checkbox複選免費加值服務,而可選取的服務數目有上限,或具有"選A服務就不能再挑B服務"之類的特殊限制。這類的檢核要求,看起來無法單靠在Checkbox加註data-val-*搞定,多半需要額外加工,以下便是我自己慣用處理方式的分享。
針對這種情境,我多半會在網頁另外偷藏一個<input type="hidden">隱藏欄位,當使用者點選Checkbox時,會觸發程式邏輯將多個Checkbox的勾選結果合併成單一字串(如"選項1|選項5|選項8")寫入隱藏欄位;而實際送至伺服器端的其實是隱藏欄位中的合併字串,而非各個Checkbox的值。加入這番設計,檢核對象便可縮小到單一隱藏欄位,不用管使用者實際勾選的那些Checkbox。不過因為我在專案中大量使用內嵌式的檢核訊息顯示,使用<input type="hidden" />無法決定訊息顯示位置,得改用<input type="text" style="visibility: hidden; width: 0px" />,才能可以滿足"隱藏不可見,但在網頁上有其顯示位置座標"的要求。
下一步要將Checkbox的勾選結果即時反應到隱藏欄位上,決定還是採Unobtrusive方式謙卑地完成才夠酷。在隱藏欄位上定義data-multi-sel-cbx-selector Attribute,指定"input.boo-checkes"、"#check-group input:checkbox"之類jQuery選擇器,定義其關聯的Checkbox。程式會對這些Checkbox加上Click事件,一旦任何一個被勾選或解除勾選,就重新找出這群Checkbox中被勾選者,取其值以特定字元(如"|")合併成單一字串,將其設為隱藏欄位的內容。合併時用來分隔的字元如果不要用預設的"|",也可以透過data-multi-sel-sep-char Attribute另行指定。此外,某些時候會透過程式變動隱藏欄位的值,希望也要能反應為Checkbox的勾選狀態,做法是宣告"mapValue"事件加入邏輯,在修改隱藏欄位內容後觸發即可,例如: $("#hidden_input").val("option1|option2").trigger("mapValue");
以上工作完成後,剩下的就跟一般掛檢核邏輯的做法沒什麼兩樣,透過data-val-required, data-val-custRule對隱藏欄位加上必選或自訂檢核規則就OK了。
來看個實例! 假想市調問卷有個題目,要求使用者複選自己最常用的電子小裝置,至少一樣,最多三樣。我們可將隱藏欄位放在所有Checkbox的最前方,讓內嵌式檢核訊息出現在左上角(或者你也可以任意調整隱藏欄位的擺放位置,高興就好)。其他部分如先前的介紹,透過data-multi-sel-cbx-selector="#ulGadgets :checkbox"指定隱藏欄位要跟哪些Checkbox關聯,然後靠data-val-required 限定至少要選一個,再加上自訂檢核條件(data-val-multiSelect)限制不可選取超過3個。
以下是程式碼,另有線上展示可供把玩,歡迎大家參考回饋。
<!DOCTYPE html>
<html>
<head>
<title>Multiple-Selection Field Validation Example</title>
<script src="Scripts/jquery-1.6.3.js"> </script>
<script src="Scripts/jquery.validate.js"> </script>
<script src="Scripts/jquery.validate.unobtrusive.js"> </script>
<script src="Scripts/jquery.validate.inline.js"> </script>
<link href="Content/validationEngine.jquery.css" rel="stylesheet" type="text/css" />
<script>
$(function () {
//透過Unobtrusive方式將隱藏欄位能自動取得Checkbox的勾選結果
//實務上這段Script可提取成獨立JS檔,方便重複利用
//找出有設data-multi-sel-cbx-selector的欄位
$("input[data-multi-sel-cbx-selector]").each(function () {
var $input = $(this);
//若有data-multi-sel-sep-char,就使用自訂的分隔字元,
//未指定定時,預設使用"|"分隔
var sepChar = $input.data("multiSelSepChar") || "|";
//由data-multi-sel-cbx-selector取出jQuery selector
//找到其關聯的Checkbox進行雙向繫結
var $cbxes = $($input.data("multiSelCbxSelector"));
//在每一個關聯Checkbox上加掛Click事件
$cbxes.click(function () {
//將所有勾選的值串成單一字串
var ary = [];
$cbxes.filter(":checked").each(function () {
ary.push(this.value);
});
//將合併的單一字串設為隱藏欄位的值
//並呼叫"focusout"事件立即觸發檢核
$input.val(ary.join(sepChar)).focusout();
});
//另外宣告一個mapValue事件,用來將隱藏欄位內容反應成Checkbox勾選狀態
$input.bind("mapValue", function () {
var ary = this.value.split(sepChar);
$cbxes.each(function () {
//由Checkbox value是否在其中決定checked
this.checked = $.inArray(this.value, ary) != -1;
});
});
});
});
</script>
<script>
//自訂檢核邏輯,以|分隔字元拆解出複選值陣列
//由陣列數目限定複選數量不可超過3個
jQuery.validator.addMethod("multiSelectChk",
function (value, elem, params) {
var count = value.split('|').length;
if (count > 3) return false;
return true;
}, '');
jQuery.validator.unobtrusive.adapters.add(
"multiSelect", [],
function (options) {
options.rules["multiSelectChk"] = true;
options.messages['multiSelectChk'] = options.message;
});
$(function () {
$("#form1").makeValidationInline();
});
</script>
<style>
body,table,input { font-size: 9pt; }
td { border: 1px solid gray; padding: 5px; }
#ulGadgets
{
list-style-type: none; margin: 0px;
padding: 0px;
}
#ulGadgets li { float: left; }
</style>
</head>
<body>
<form id="form1" method="get" action="MultSelFieldValidation.htm">
<table style="margin-top: 50px;">
<tr>
<td style="width: 150px; text-align: right; vertical-align: top;">
Frequently Used Gadgets</td>
<td style="width: 400px">
<input type="text" id="txtGadgets" name="txtGadgets"
style="visibility: hidden; position: absolute; width: 0px;"
data-val="true" data-val-required="Please choose at least one option"
data-val-multiSelect="You cannot choose more than 3 options"
data-multi-sel-cbx-selector="#ulGadgets :checkbox"
/>
<ul id="ulGadgets">
<li><input type="checkbox" value="Watch" />Watch</li>
<li><input type="checkbox" value="MP3Player" />MP3 Player</li>
<li><input type="checkbox" value="FlashDrive" />USB Flash Drive</li>
<li><input type="checkbox" value="MobiePhone" />Mobile Phone</li>
<li><input type="checkbox" value="PDA" />PDA</li>
<li><input type="checkbox" value="GPS" />GPS</li>
<li><input type="checkbox" value="Tablet" />Tablet or Slate PC</li>
</ul>
<div style="clear: both; margin: 5px; color: Gray;">
(Multiple selection,
please select at least one, but not more than three)</div>
</td>
</tr>
</table>
<input type="submit" value="Submit" />
</form>
</body>
</html>
Comments
Be the first to post a comment