用页面脚本扩展mvc自动添加的验证

mvc中可以用DataAnnotations来对模型进行验证

当在页面中引入

jquery,jquery.validate,jquery.validate.unobtrusive这3个脚本的时候,会根据model上的设置自动生成验证

[Required]
public string Email { get; set; }
比如我有这样的字段,他会在页面上生成必填的验证
image
默认错误信息是用span来呈现的
image
如果不希望使用默认设置,而希望在不同的页面,或在同一个页面的不同表单做不同的设置,用mvc自动生成的就很难实现了。
 
其实validate本身是可以设置的
$(function () {
    $("form").validate({
        errorElement: "div",
        rules: { Email: { email: true,required:true } }
    });
});

如类似上面的代码

image

image

错误信息是用div来呈现的。

如果,在一个引入了jquery.validate.unobtrusive的页面中,写入上面的语句,是没有用的

<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script>
    $(function () {
        $("form").validate({
            errorElement: "div",
            rules: { Email: { email: true } }
        });
    });

……

类似这样。因为unobtrusive先执行了,所以页面中用validate设置的无效

让引入的js后执行

<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript" defer></script>

在引用的时候加上defer,这样虽然引入的代码写在前面,但是执行是在后面

imageimage

加上以后,可以看到,页面中的代码起了作用。但是自动生成又失效了。必填验证没有了。

查看unobtrusive的代码发现

function validationInfo(form) {
    var $form = $(form),
        result = $form.data(data_validation);
    //如果直接在页面上用validate写了验证,就不做
        if (!result) {
           ……
       }

    return result;
}

他会先去看有没有验证信息,如果没有,才加,有就不加了。

只好自己修改一下了。

首先,仍然是通过对某一个表单进行设置,这样同一个页面上有多个表单的时候,可以其中一个变,而另一个不变

image

写一个扩展方法,传入设置,并记录在调用的对象上。其中,set_validation是自定义的一个字符串,相当于字典key

$.extend($.fn, {
  
setValidation:function(opt) {           
      
$.data(this[0],set_validation,opt);
    }
});

修改validationInfo方法 if(!result)中的部分

var defaults = {
    errorClass: "input-validation-error",
    errorElement: "span",
    errorPlacement: $.proxy(onError, form),
    invalidHandler: $.proxy(onErrors, form),
    messages: {},
    rules: {},
    success: $.proxy(onSuccess, form)
};
var opt = $form.data(set_validation);               
var setting = $.extend(defaults, opt);
result = {
    options: setting,

……

把他直接写在options里的拿出来作为默认值

读取通过setValidation方法加到表单上的设置

把设置覆盖到默认值上作为最终的设置值。

到目前为止,设置erroeElement等已经可以生效,但是rules和messages还是无效。

原因在于

parseElement: function (element, skipAttach) {

方法中有这么两句

valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};

他把rules和messages都清空了。我尝试不清空,但是发现有问题。我懒的研究他具体是怎么把那些规则加进去的了。好在在后面发现了一句

jQuery.extend(rules, { "__dummy__": true });

在方法基本已经结束的位置他还对rules做了操作

于是在清空之前,记录下原始数据,在这里附加原始数据

valInfo = validationInfo(form);
//记录设置
var settingRule = valInfo.options.rules[element.name];
var settingMessage = valInfo.options.messages[element.name];
valInfo.options.rules[element.name] = rules = {};
valInfo.options.messages[element.name] = messages = {};

最后

//附加设置
jQuery.extend(rules, { "__dummy__": true }, settingRule);
jQuery.extend(messages, settingMessage);

到此rules和messages也可以加进来了。

页面调用

$(function () {
    $("#form1").setValidation({
        errorElement:"div",
        rules: { Email: { email: true } }
    });
});

image

上面的表单form1附加了用div显示,及email格式验证

修改过的unobtrusive如下

   1: /// <reference path="jquery-1.5.1.js" />
   2: /// <reference path="jquery.validate.js" />
   3:  
   4: /*!
   5: ** Unobtrusive validation support library for jQuery and jQuery Validate
   6: ** Copyright (C) Microsoft Corporation. All rights reserved.
   7: */
   8:  
   9: /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
  10: /*global document: false, jQuery: false */
  11:  
  12: /*modify by czcz1024*/
  13: (function ($) {
  14:     var $jQval = $.validator,
  15:         adapters,
  16:         set_validation="unobtrusiveValidationSettings"
  17:         data_validation = "unobtrusiveValidation";
  18:  
  19:     function setValidationValues(options, ruleName, value) {
  20:         options.rules[ruleName] = value;
  21:         if (options.message) {
  22:             options.messages[ruleName] = options.message;
  23:         }
  24:     }
  25:  
  26:     function splitAndTrim(value) {
  27:         return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
  28:     }
  29:  
  30:     function escapeAttributeValue(value) {
  31:         // As mentioned on http://api.jquery.com/category/selectors/
  32:         return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
  33:     }
  34:  
  35:     function getModelPrefix(fieldName) {
  36:         return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
  37:     }
  38:  
  39:     function appendModelPrefix(value, prefix) {
  40:         if (value.indexOf("*.") === 0) {
  41:             value = value.replace("*.", prefix);
  42:         }
  43:         return value;
  44:     }
  45:  
  46:     function onError(error, inputElement) {  // 'this' is the form element
  47:         var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
  48:             replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
  49:  
  50:         container.removeClass("field-validation-valid").addClass("field-validation-error");
  51:         error.data("unobtrusiveContainer", container);
  52:  
  53:         if (replace) {
  54:             container.empty();
  55:             error.removeClass("input-validation-error").appendTo(container);
  56:         }
  57:         else {
  58:             error.hide();
  59:         }
  60:     }
  61:  
  62:     function onErrors(form, validator) {  // 'this' is the form element
  63:         var container = $(this).find("[data-valmsg-summary=true]"),
  64:             list = container.find("ul");
  65:  
  66:         if (list && list.length && validator.errorList.length) {
  67:             list.empty();
  68:             container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
  69:  
  70:             $.each(validator.errorList, function () {
  71:                 $("<li />").html(this.message).appendTo(list);
  72:             });
  73:         }
  74:     }
  75:  
  76:     function onSuccess(error) {  // 'this' is the form element
  77:         var container = error.data("unobtrusiveContainer"),
  78:             replace = $.parseJSON(container.attr("data-valmsg-replace"));
  79:  
  80:         if (container) {
  81:             container.addClass("field-validation-valid").removeClass("field-validation-error");
  82:             error.removeData("unobtrusiveContainer");
  83:  
  84:             if (replace) {
  85:                 container.empty();
  86:             }
  87:         }
  88:     }
  89:  
  90:     function validationInfo(form) {
  91:         var $form = $(form),
  92:             result = $form.data(data_validation);
  93:         //如果直接在页面上用validate写了验证,就不做
  94:             if (!result) {
  95:                 //默认值
  96:                 var defaults = {
  97:                     errorClass: "input-validation-error",
  98:                     errorElement: "span",
  99:                     errorPlacement: $.proxy(onError, form),
 100:                     invalidHandler: $.proxy(onErrors, form),
 101:                     messages: {},
 102:                     rules: {},
 103:                     success: $.proxy(onSuccess, form)
 104:                 };
 105:                 var opt = $form.data(set_validation);               
 106:                 var setting = $.extend(defaults, opt);
 107:                 result = {
 108:                     options: setting,
 109:                     attachValidation: function () {
 110:                         $form.validate(this.options);
 111:                     },
 112:                     validate: function () {  // a validation function that is called by unobtrusive Ajax
 113:                         $form.validate();
 114:                         return $form.valid();
 115:                     }
 116:                 };
 117:             $form.data(data_validation, result);
 118:         }
 119:  
 120:         return result;
 121:     }
 122:  
 123:     $jQval.unobtrusive = {
 124:         adapters: [],
 125:  
 126:         parseElement: function (element, skipAttach) {
 127:             /// <summary>
 128:             /// Parses a single HTML element for unobtrusive validation attributes.
 129:             /// </summary>
 130:             /// <param name="element" domElement="true">The HTML element to be parsed.</param>
 131:             /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
 132:             /// validation to the form. If parsing just this single element, you should specify true.
 133:             /// If parsing several elements, you should specify false, and manually attach the validation
 134:             /// to the form when you are finished. The default is false.</param>
 135:             var $element = $(element),
 136:                 form = $element.parents("form")[0],
 137:                 valInfo, rules, messages;
 138:  
 139:             if (!form) {  // Cannot do client-side validation without a form
 140:                 return;
 141:             }
 142:  
 143:             valInfo = validationInfo(form);
 144:             //记录设置
 145:             var settingRule = valInfo.options.rules[element.name];
 146:             var settingMessage = valInfo.options.messages[element.name];
 147:             valInfo.options.rules[element.name] = rules = {};
 148:             valInfo.options.messages[element.name] = messages = {};
 149:  
 150:             $.each(this.adapters, function () {
 151:                 var prefix = "data-val-" + this.name,
 152:                     message = $element.attr(prefix),
 153:                     paramValues = {};
 154:  
 155:                 if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)
 156:                     prefix += "-";
 157:  
 158:                     $.each(this.params, function () {
 159:                         paramValues[this] = $element.attr(prefix + this);
 160:                     });
 161:  
 162:                     this.adapt({
 163:                         element: element,
 164:                         form: form,
 165:                         message: message,
 166:                         params: paramValues,
 167:                         rules: rules,
 168:                         messages: messages
 169:                     });
 170:                 }
 171:             });
 172:  
 173:             //附加设置
 174:             jQuery.extend(rules, { "__dummy__": true }, settingRule);
 175:             jQuery.extend(messages, settingMessage);
 176:  
 177:             if (!skipAttach) {
 178:                 valInfo.attachValidation();
 179:             }
 180:         },
 181:  
 182:         parse: function (selector) {
 183:             /// <summary>
 184:             /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
 185:             /// with the [data-val=true] attribute value and enables validation according to the data-val-*
 186:             /// attribute values.
 187:             /// </summary>
 188:             /// <param name="selector" type="String">Any valid jQuery selector.</param>
 189:             $(selector).find(":input[data-val=true]").each(function () {
 190:                 $jQval.unobtrusive.parseElement(this, true);
 191:             });
 192:  
 193:             $("form").each(function () {
 194:                 var info = validationInfo(this);
 195:                 if (info) {
 196:                     info.attachValidation();
 197:                 }
 198:             });
 199:         }
 200:     };
 201:  
 202:     adapters = $jQval.unobtrusive.adapters;
 203:  
 204:     adapters.add = function (adapterName, params, fn) {
 205:         /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
 206:         /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
 207:         /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
 208:         /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
 209:         /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
 210:         /// mmmm is the parameter name).</param>
 211:         /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
 212:         /// attributes into jQuery Validate rules and/or messages.</param>
 213:         /// <returns type="jQuery.validator.unobtrusive.adapters" />
 214:         if (!fn) {  // Called with no params, just a function
 215:             fn = params;
 216:             params = [];
 217:         }
 218:         this.push({ name: adapterName, params: params, adapt: fn });
 219:         return this;
 220:     };
 221:  
 222:     adapters.addBool = function (adapterName, ruleName) {
 223:         /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
 224:         /// the jQuery Validate validation rule has no parameter values.</summary>
 225:         /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
 226:         /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
 227:         /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
 228:         /// of adapterName will be used instead.</param>
 229:     /// <returns type="jQuery.validator.unobtrusive.adapters" />
 230:  
 231:         if (adapterName == "dateiso") adapterName = "dateISO";
 232:         return this.add(adapterName, function (options) {
 233:             setValidationValues(options, ruleName || adapterName, true);
 234:         });
 235:     };
 236:  
 237:     adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
 238:         /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
 239:         /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
 240:         /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
 241:         /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
 242:         /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
 243:         /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
 244:         /// have a minimum value.</param>
 245:         /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
 246:         /// have a maximum value.</param>
 247:         /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
 248:         /// have both a minimum and maximum value.</param>
 249:         /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
 250:         /// contains the minimum value. The default is "min".</param>
 251:         /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
 252:         /// contains the maximum value. The default is "max".</param>
 253:         /// <returns type="jQuery.validator.unobtrusive.adapters" />
 254:         return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
 255:             var min = options.params.min,
 256:                 max = options.params.max;
 257:  
 258:             if (min && max) {
 259:                 setValidationValues(options, minMaxRuleName, [min, max]);
 260:             }
 261:             else if (min) {
 262:                 setValidationValues(options, minRuleName, min);
 263:             }
 264:             else if (max) {
 265:                 setValidationValues(options, maxRuleName, max);
 266:             }
 267:         });
 268:     };
 269:  
 270:     adapters.addSingleVal = function (adapterName, attribute, ruleName) {
 271:         /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
 272:         /// the jQuery Validate validation rule has a single value.</summary>
 273:         /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
 274:         /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
 275:         /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
 276:         /// The default is "val".</param>
 277:         /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
 278:         /// of adapterName will be used instead.</param>
 279:         /// <returns type="jQuery.validator.unobtrusive.adapters" />
 280:         return this.add(adapterName, [attribute || "val"], function (options) {
 281:             setValidationValues(options, ruleName || adapterName, options.params[attribute]);
 282:         });
 283:     };
 284:  
 285:     $jQval.addMethod("__dummy__", function (value, element, params) {
 286:         return true;
 287:     });
 288:  
 289:     $jQval.addMethod("regex", function (value, element, params) {
 290:         var match;
 291:         if (this.optional(element)) {
 292:             return true;
 293:         }
 294:  
 295:         match = new RegExp(params).exec(value);
 296:         return (match && (match.index === 0) && (match[0].length === value.length));
 297:     });
 298:  
 299:     adapters.addSingleVal("accept", "exts").addSingleVal("regex", "pattern");
 300:     adapters.addBool("creditcard").addBool("date").addBool("dateiso").addBool("digits").addBool("email").addBool("number").addBool("url");
 301:     adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
 302:     adapters.add("equalto", ["other"], function (options) {
 303:         var prefix = getModelPrefix(options.element.name),
 304:             other = options.params.other,
 305:             fullOtherName = appendModelPrefix(other, prefix),
 306:             element = $(options.form).find(":input[name=" + escapeAttributeValue(fullOtherName) + "]")[0];
 307:  
 308:         setValidationValues(options, "equalTo", element);
 309:     });
 310:     adapters.add("required", function (options) {
 311:         // jQuery Validate equates "required" with "mandatory" for checkbox elements
 312:         if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
 313:             setValidationValues(options, "required", true);
 314:         }
 315:     });
 316:     adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
 317:         var value = {
 318:             url: options.params.url,
 319:             type: options.params.type || "GET",
 320:             data: {}
 321:         },
 322:             prefix = getModelPrefix(options.element.name);
 323:  
 324:         $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
 325:             var paramName = appendModelPrefix(fieldName, prefix);
 326:             value.data[paramName] = function () {
 327:                 return $(options.form).find(":input[name='" + escapeAttributeValue(paramName) + "']").val();
 328:             };
 329:         });
 330:  
 331:         setValidationValues(options, "remote", value);
 332:     });
 333:     //扩展方法,记录设置的参数
 334:     $.extend($.fn, {
 335:         setValidation: function (opt) {            
 336:             $.data(this[0],set_validation,opt);
 337:         }
 338:     });
 339:  
 340:     $(function () {
 341:         $jQval.unobtrusive.parse(document);
 342:     });
 343: } (jQuery));

另外,之前的文章中,介绍过如何通过设置DataType(DataType.Date)就自动生成日期类型的验证

如果使用validation提供的date,只能验证2011/1/1 这样斜杠形式的,而不能验证2011-1-1横杠形式。要验证横杠需要用到的是dateISO,注意是区分大小写的,ISO必须是大写。但是改c#中date为dateISO就悲剧了。

Validation type names in unobtrusive client validation rules must consist of only lowercase letters. Invalid name: "dateISO", client rule type: mvc4.Models.ModelClientValidationDateRule

只能有小写字母,不知道为什么只能是小写。

那这就小写吧。还是得改unobtrusive

adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");

首先找到这句,发现他只添加date验证,不添加dateiso验证,加上

adapters.addBool("creditcard").addBool("date").

addBool("dateiso"

).addBool("digits").addBool("email").addBool("number").addBool("url");

然后找到addBool方法在return之前加上

if (adapterName == "dateiso") adapterName = "dateISO";

最终调用validate的时候,validate中的方法名是dateISO。

下载

原文地址:https://www.cnblogs.com/czcz1024/p/2212708.html