mvc中可以用DataAnnotations来对模型进行验证
当在页面中引入
jquery,jquery.validate,jquery.validate.unobtrusive这3个脚本的时候,会根据model上的设置自动生成验证
[Required]
public string Email { get; set; }
比如我有这样的字段,他会在页面上生成必填的验证
默认错误信息是用span来呈现的
如果不希望使用默认设置,而希望在不同的页面,或在同一个页面的不同表单做不同的设置,用mvc自动生成的就很难实现了。
其实validate本身是可以设置的
$(function () { $("form").validate({ errorElement: "div", rules: { Email: { email: true,required:true } } }); });
如类似上面的代码
错误信息是用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,这样虽然引入的代码写在前面,但是执行是在后面
加上以后,可以看到,页面中的代码起了作用。但是自动生成又失效了。必填验证没有了。
查看unobtrusive的代码发现
function validationInfo(form) { var $form = $(form), result = $form.data(data_validation); //如果直接在页面上用validate写了验证,就不做 if (!result) { ……
} return result; }
他会先去看有没有验证信息,如果没有,才加,有就不加了。
只好自己修改一下了。
首先,仍然是通过对某一个表单进行设置,这样同一个页面上有多个表单的时候,可以其中一个变,而另一个不变
写一个扩展方法,传入设置,并记录在调用的对象上。其中,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 } } }); });
上面的表单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就悲剧了。
只能有小写字母,不知道为什么只能是小写。
那这就小写吧。还是得改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。