Issue with chaining Required Field and Regular Expression validators for Textbox controls
我正在尝试使用 ASP.net 实现表单验证,我已经尝试了此处建议的所有解决方案,但迄今为止最好的解决方案是在 aspsnippets.com 上。
我的代码如下:
1 2 | <asp:RegularExpressionValidator runat="server" ControlToValidate="tEMail" ValidationExpression="\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"/> |
Javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <script type="text/javascript"> function WebForm_OnSubmit() { if (typeof (ValidatorOnSubmit) =="function" && ValidatorOnSubmit() == false) { for (var i in Page_Validators) { try { var control = document.getElementById(Page_Validators[i].controltovalidate); if (!Page_Validators[i].isvalid) { control.className ="error"; } else { control.className =""; } } catch (e) { } } return false; } return true; } function WebForm_OnBlur() { for (var i in Page_Validators) { try { var control = document.getElementById(Page_Validators[i].controltovalidate); if (!Page_Validators[i].isvalid) { control.className ="error"; } else { control.className =""; } } catch (e) { } } return false; } |
问题是电子邮件字段仅验证正则表达式。如果我更改验证器的顺序,它只会验证所需的表达式。
可能的问题是代码循环遍历所有验证器,但不会一次比较引用相同控件的验证器。这会导致只在控件上应用最后一个验证器条件。
The possible problem is that the code loops through all the validators but does not compare the ones that reference the same control at once. This causes only the last validator condition to be applied on the control.
是的,这确实是问题所在。要修复它,您可以执行以下操作:
在
1 2 3 4 5 6 7 8 9 | function WebForm_OnBlur(control) { for (var i = 0; i < control.Validators.length; i++) { if (!control.Validators[i].isvalid) { control.className ="error"; return; } } control.className =""; } |
在
1 |
在
1 2 3 4 5 6 7 8 9 10 11 | function WebForm_OnSubmit() { if (typeof(ValidatorOnSubmit) ==="function" && ValidatorOnSubmit() === false) { for (var i = 0; i < Page_Validators.length; i++) { var control = document.getElementById(Page_Validators[i].controltovalidate); if (Page_Validators[i] === control.Validators[0]) // minor optimization WebForm_OnBlur(control); } return false; } return true; } |
通过替换下面的代码片段解决了这个问题。为了更正,我们必须遍历一个控件的所有验证器,然后我们应该决定它是否必须用错误类标记。在此之后,您的代码将按预期工作。
更换循环
1 2 3 4 5 6 7 8 9 10 11 | for (var i in Page_Validators) { try { var control = document.getElementById(Page_Validators[i].controltovalidate); if (!Page_Validators[i].isvalid) { control.className ="error"; } else { control.className =""; } } catch (e) { } } |
使用以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | for (var j in Page_Validators) { try { var control = document.getElementById(Page_Validators[j].controltovalidate); var IsError = false; for (var i in control.Validators) { if (!control.Validators[i].isvalid) { IsError = true; } } if (IsError) control.className ="error"; else control.className =""; } catch (e) { } } |
我刚刚运行了它,它运行良好 :) 试试这个解决方案!
除了@MichaelLiu,您还可以制作自己的继承自
例如:
验证器.cs
注意我们如何添加
我们还设置了其他属性,因此您不必每次都设置它们,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | public class RequiredFieldValidator : CustomValidator { public string CssControlErrorClass { get; set; } public RequiredFieldValidator() { ClientValidationFunction ="validators.required"; ValidateEmptyText = true; } public string InitialValue { get { object o = ViewState["InitialValue"]; return ((o == null) ? String.Empty : (string)o); } set { ViewState["InitialValue"] = value; } } protected override void Render(HtmlTextWriter writer) { //Have to add attributes BEFORE the beginning tag is written to the stream writer.AddAttribute("data-errorClass", CssControlErrorClass); writer.AddAttribute("data-for", GetControlRenderID(ControlToValidate)); base.Render(writer); } protected override bool EvaluateIsValid() { //Default implementation of the RequiredFieldValidation validator string controlValue = GetControlValidationValue(ControlToValidate); if (controlValue == null) { return true; } var result = (!controlValue.Trim().Equals(InitialValue.Trim())); //Check to see if validation failed, if it did, add the class to the control to validate if (!result) { var control = (WebControl) NamingContainer.FindControl(ControlToValidate); //Didn't look into it too much, but the validators fire twice for some reason if(!control.CssClass.Contains(CssControlErrorClass)) control.CssClass +="" + CssControlErrorClass; } return result; } } public class RegularExpressionValidator : CustomValidator { public string CssControlErrorClass { get; set; } public string ValidationExpression { get { object o = ViewState["ValidationExpression"]; return ((o == null) ? String.Empty : (string)o); } set { try { Regex.IsMatch(String.Empty, value); } catch (Exception e) { throw new HttpException(string.Format("{0} - {1}","Validator_bad_regex", value), e); } ViewState["ValidationExpression"] = value; } } public RegularExpressionValidator() { ClientValidationFunction ="validators.regex"; } protected override void Render(HtmlTextWriter writer) { //Have to add attributes BEFORE the beginning tag is written to the stream writer.AddAttribute("data-errorClass", CssControlErrorClass); writer.AddAttribute("data-regex", ValidationExpression); writer.AddAttribute("data-for", GetControlRenderID(ControlToValidate)); base.Render(writer); } protected override bool EvaluateIsValid() { //Default implementation of the RegularExpressionFieldvalidator string controlValue = GetControlValidationValue(ControlToValidate); if (controlValue == null || controlValue.Trim().Length == 0) { return true; } try { Match m = Regex.Match(controlValue, ValidationExpression); var result = (m.Success && m.Index == 0 && m.Length == controlValue.Length); //Check to see if validation failed, if it did, add the class to the control to validate if (!result) { var control = (WebControl) NamingContainer.FindControl(ControlToValidate); //Didn't look into it too much, but the validators fire twice for some reason if (!control.CssClass.Contains(CssControlErrorClass)) control.CssClass +="" + CssControlErrorClass; } return result; } catch { return true; } } } |
验证器.js
由于在前面的类中我们预先定义了 javascript 函数,我们可以像这样添加一个简单的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | var v = window.validators = window.validators || { errorControlAttributeName:"data-for", errorClassAttributeName:"data-errorClass", regexAttributeName:"data-regex", required: function(src, args) { var controlId = src.getAttribute(v.errorControlAttributeName), errorClass = src.getAttribute(v.errorClassAttributeName), input = document.getElementById(controlId); var isValid = (args.Value !==""); v._toggleInputErrorState(input, errorClass, isValid); args.IsValid = isValid; return; }, regex: function(src, args) { var controlId = src.getAttribute(v.errorControlAttributeName), errorClass = src.getAttribute(v.errorClassAttributeName), regexString = src.getAttribute(v.regexAttributeName), input = document.getElementById(controlId), regex = new RegExp(regexString); var isValid = regex.test(args.Value); v._toggleInputErrorState(input, errorClass, isValid); args.IsValid = isValid; return; }, /************* Helper functions ***********/ _toggleInputErrorState: function (inputEl, errorClass, isValid) { if (!isValid) { if (!v._hasClass(inputEl, errorClass)) { inputEl.className +="" + errorClass; } } else { if (v._hasClass(inputEl, errorClass)) { //Not the most performant, but is sure is easiest inputEl.className = inputEl.className.replace("" + errorClass,""); } } }, _hasClass: function(el, className) { return el.className.indexOf(className) != -1 ? true : false; }, } |
非常简单的验证库,您可以轻松地扩展您真正感兴趣的东西。
默认.aspx
之后,您可以将控件放入您的页面:
1 2 | <Validators:RequiredFieldValidator runat="server" CssControlErrorClass="input-validation-error" ControlToValidate="Test" ErrorMessage="REQUIRED BRO!"></Validators:RequiredFieldValidator> <Validators:RegularExpressionValidator runat="server" ValidationExpression="[0-9]" CssControlErrorClass="input-validation-error" ControlToValidate="Test" ErrorMessage="REQUIRED RegEx BRO!"></Validators:RegularExpressionValidator> |
这是最好的方法吗?可能不是,(这两个使用微软提供的默认实现)那里有比我更聪明的人,而且我不经常使用 WebForms。我看到的最大好处是您获得了一些可重用的代码,使用熟悉的语法,最终将包含您所有的验证需求,而不是每次都使用 js 来获得您想要的验证"规则"。
您可以在 javascript 中尝试 Page_ClientValidate(),而不是遍历验证器。
我相信这将验证页面上的所有验证器。
如果要验证受特定验证组绑定的特定控件,它还接受参数"验证组名称"。