zoukankan      html  css  js  c++  java
  • 用页面脚本扩展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。

    下载

  • 相关阅读:
    eg_5
    浅谈Java中的Hashmap
    java中方法传入参数时:值传递还是址传递?
    重温概率学(一)期望、均值、标准差、方差
    博客搬家
    golang sync/atomic
    单机配置kafka和zookeeper
    异步消息队列组件
    2017总结
    看完轻松年薪30w+
  • 原文地址:https://www.cnblogs.com/czcz1024/p/2212708.html
Copyright © 2011-2022 走看看