接連介紹了謙卑式jQuery檢核整合Server端檢核自訂檢核條件,針對應用時常遇問題,發現還缺了一塊: 當使用AJAX方式動態更新<input>內容或檢核設定時,應如何讓檢核設定生效?

依據jquery.validate.unobtrusive.js的運作原理,它會在網頁載入後立即呼叫$.validator.unobtrusive.parse(document)解析讀取元素的data-val-*標示,完成檢核條件設定,這也意味著事後加入<input>或追加data-val-*將不會被納入表單送出前的檢核項目。Brad Wilson在文章中有一節"Parsing New HTML For Validation"提到可呼叫jQuery.validator.unobtrusive.parse()或jQuery.validator.unobtrusive.parseElement()重新解析並設定檢核條件,但經實測,除非整個<form>是動態重新產生的,否則parse()/parseElement()並無預期效果,<form>的檢核條件仍維持onload事件所讀取到的內容。

追進原始碼,發現問題出在jquery.validate.unobtrusive.js透過$("form”).validate(…)重新設定表單撿核條件,但在jquery.validate.js中,form一旦被validate()設定過,validator物件就會被保存在$(theForm).data(“validator”),之後再呼叫validate(options),會只傳回原先的validator物件,而不會將options的內容併入validator:

        validate: function (options) {
 
            // if nothing is selected, return nothing; can't chain anyway
            if (!this.length) {
                options && options.debug && window.console && //...省略...
                return;
            }
 
            // check if a validator for this form was already created
            var validator = $.data(this[0], 'validator');
            if (validator) {
                return validator;
            }

以此推論,除非form本身尚未建立.data(“validator”),否則呼叫.validate(options)不會有任何效果。但在jquery.validate.unobtrusive.js中,網頁載入時就已對既有<form>做過.validate(),也都已建立validator物件,除非<form>為事後動態新增,parse()或parseElement()無力變更一載入時就讀取好的檢核設定。針對這個問題,我找到的解套方法是手動將$(theForm).removeData(“validator”),在下次parse()/parseElement()時便能砍掉重練。

以下是程式範例。我動態新增了一個<input id="tDyna">,並為<input id="tReq">增加data-val-number="..."數字檢核條件,程式中示範了三種寫法,並已在註解中說明用法與效果差別:

<!DOCTYPE html>
 
<html>
<head>
    <title>Unobtrusive jQuery Validation for Dynamic Content</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.2.js" 
     type="text/javascript"> </script>   
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8.1/jquery.validate.js" 
     type="text/javascript"> </script>   
    <script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js" 
     type="text/javascript"> </script>  
    <style type="text/css">
body,input { font-size: 9pt; }     
.input-validation-error { border: 1px solid #ff0000 }
.input-validation-valid  { border: 1px solid #00ff00 }
.field-validation-error { color: #ff0000 }
.field-validation-valid { display: none }
.validation-summary-errors { font-weight: bold; color: #ff0000 }
.validation-summary-valid { display: none }
    </style>
    <script type="text/javascript">
        $(function () {
            //tReq新增數字檢核
            $("#tReq").attr("data-val-number", "須為數字(動態加上的檢核)");
            //無中生有新增一個<input id=tDyna>,並加上必填檢核
            var id = "tDyna";
            $("#dvDyna").append("<input type='text' id='" + id + "' />");
            $("#tDyna").attr({ 
                name: id,
                "data-val": "true",
                "data-val-required": "不可空白(動態加上的檢核)",
             }).after("<span data-valmsg-for='" + id + "' />");
             //要先移除原有設定
             $("#form1").removeData("validator");
             
             //方法一,傳入新增檢核設定的元素,包含該元素的<form>會重設檢核條件
             //$.validator.unobtrusive.parseElement(document.getElementById("tDyna"));
             
             //方法二,傳入內含<input data-val="true">元素的容器selector,
             //將重新解析容器內的元素的data-val-*設定,接著所有的<form>會更新檢核規則
             //$.validator.unobtrusive.parse("#dvDyna");
 
           //在本案例中方法一、二都只更新了<input id='tDyna'>。<input id='tReq'>新增的
             //data-val-number並未被解析生效,我們可擴大解析範圍改善這個問題
             $.validator.unobtrusive.parse("#form1"); //或parse(document)亦可
 
        });
    </script>
</head>
<body>
<form id="form1">
<div>
<input type="text" id="tReq" name="tReq" 
 data-val = "true" data-val-required = "不可空白" />
<span data-valmsg-for="tReq"></span>
</div>
<div id="dvDyna">
</div>
<input type="submit" value="Submit" />
</form>
</body>
</html>

值得注意的是,$(theForm).removeData(“validator”)的解法會移除原有的檢核設定,如果曾另外透過程式動態修改validator內容,移除validator將導致事後修改一併失效。針對這個缺點,XHalent提出了更優雅的解法,撰寫了一支parseDynamicContent() Plugin可將新增的檢核條件合併進原有的validator物件中,但必須多載入jQuery Plugin,此一解決方案也一併提供大家參考。


Comments

Be the first to post a comment

Post a comment