jquery validate ":hidden"

  • 328
  • 0
  • 2016-03-16

jquery validate default setting ignore ":hidden", after version 1.9.0. http://bassistance.de/2011/10/07/release-validation-plugin-1-9-0/

在 asp.net mvc使用 [attribute]驗證輸入資料的時候,有個 radio button一直沒有觸發驗證…卡了半天,把頁面其他欄位拿掉還是不動,一怒之下把 html, javascript複製到 jsbin居然就能跑?
想不到什麼好方法,一項一項比對差異,本機 jquery.validate是 1.10,jsbin上拿別人的範例來改是載入 cdn的 1.8,嗯……體力耗盡,改日再戰 Orz

登登登,一日過去。

$("form").validate().element("#my_column") // 用這個方法試我的欄位到底有沒有驗證,得到 js執行錯誤,好的開始!
// 發現它會去呼叫內部的 check()
// check()會呼叫 validationTargetFor()

validationTargetFor: function(element) {
    // if radio/checkbox, validate first element in group instead
    if (this.checkable(element)) {
        element = this.findByName( element.name ).not(this.settings.ignore)[0];
    }
    return element;
},

// this.settings.ignore = ":hidden" 很熟悉的 jquery selector
// 回頭看 css,設計為了自訂 radio button style的確有隱藏 radio & checkbox

確定原因,解法就單純了:

// http://stackoverflow.com/a/8565769/4963421
$.validator.setDefaults({
    ignore: []
});
// or
$(function () {
    $('#myform').validate({ // 好像因為 unobtrusive的關係,原本的預設值有被另外複製一份,所以這樣改不會生效
        ignore: [],
        // any other options and/or rules
    });
    
    $("form").data("validator").settings.ignore = [];// 要這樣硬來
})

終於動了 Q_Q

順便記錄 MVC自訂驗證邏輯步驟:

// checkbox = true檢查 elemNames、checkbox = false檢查 falseCheckElemNames
public class CheckBoxConditionRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private const string _defaultErrorMessage = "The Value field is required.";
    private string[] _elemNames;
    private string[] _falseCheckElemNames;

    public CheckBoxConditionRequiredAttribute(string[] elemNames, string[] falseCheckElemNames = null)
    {
        _elemNames = elemNames;
        _falseCheckElemNames = falseCheckElemNames;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {// checkbox 沒值不檢查
            return null;
        }

        bool result = true, chkValue = false;
        bool.TryParse(value.ToString(), out chkValue);

        if (chkValue)
        {
            foreach (var item in _elemNames)
            {
                var itemValue = Convert.ToString(validationContext.ObjectType.GetProperty(item).GetValue(validationContext.ObjectInstance, null));
                if (string.IsNullOrEmpty(itemValue))
                {
                    result = false;
                    break;
                }
            }
        }
        else
        {// false時要填的欄位
            if (_falseCheckElemNames != null)
            {
                foreach (var item in _falseCheckElemNames)
                {
                    var itemValue = Convert.ToString(validationContext.ObjectType.GetProperty(item).GetValue(validationContext.ObjectInstance, null));
                    if (string.IsNullOrEmpty(itemValue))
                    {
                        result = false;
                        break;
                    }
                }
            }
        }
        if (!result)
        {
            string errorMsg = this.ErrorMessageString;
            if (string.IsNullOrEmpty(this.ErrorMessage))
            {
                if (this.ErrorMessageResourceType != null && !string.IsNullOrEmpty(this.ErrorMessageResourceName))
                {
                    errorMsg = ErrorMessageResourceType.GetProperty(ErrorMessageResourceName).GetValue(ErrorMessageResourceType) as string;
                }
                else
                {
                    errorMsg = _defaultErrorMessage;
                }
            }
            return new ValidationResult(errorMsg);
        }

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        string errorMsg = this.ErrorMessageString;
        if ((this.ErrorMessageResourceType == null || string.IsNullOrEmpty(this.ErrorMessageResourceName)) && string.IsNullOrEmpty(this.ErrorMessage))
        {
            errorMsg = _defaultErrorMessage;
        }

        ModelClientValidationRule rule = new ModelClientValidationRule
        {
            ErrorMessage = string.Format(errorMsg),
            ValidationType = "checkboxconditionrequired"
        };

        // 此參數一定要是小寫!
        rule.ValidationParameters.Add("obj", metadata.PropertyName);
        rule.ValidationParameters.Add("domelemnames", string.Join(",", _elemNames));
        rule.ValidationParameters.Add("falsecheckelem", string.Join(",", _falseCheckElemNames));
        yield return rule;
    }
}

[CheckBoxConditionRequired(new string[] { "input_while_true" }, falseCheckElemNames: new string[] { "input_while_false" }
    , ErrorMessageResourceType = typeof(resourceType)
    , ErrorMessageResourceName = "resourceProperty"
)]
public bool flag { get; set; }
public string input_while_true { get; set; }
public string input_while_false { get; set; }
<script src="/Scripts/jquery.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script>
$.validator.addMethod("checkboxconditionrequired", function (value, element, params) {
    var obj = $('#' + params['obj']),
        domelemNames = params['domelemnames'].split(","),
        falsecheckelem = (params["falsecheckelem"] || "").split(","),
        isChecked = obj[0].checked,
        result = true;
    if (isChecked) {
        $.each(domelemNames, function (index, value) {
            if ($("#" + value).val() == "") {
                result = false;
                return false;
            }
        });
    }
    else {
        if (falsecheckelem.length > 0) {
            $.each(falsecheckelem, function (index, value) {
                if ($("#" + value).val() == "") {
                    result = false;
                    return false;
                }
            });
        }
    }

    return result;
});

$.validator.unobtrusive.adapters.add(
    'checkboxconditionrequired', ['obj', 'domelemnames', 'falsecheckelem'],
    function (options) {
        options.rules['checkboxconditionrequired'] = {
            obj: options.params['obj'],
            domelemnames: options.params['domelemnames'],
            falsecheckelem: options.params['falsecheckelem']
        };

        if (options.message != null) {
            $.validator.messages.checkboxconditionrequired = options.message;
        }
    }
);
</script>