链接文本框控件的必填字段和正则表达式validation器的问题

我正在尝试使用ASP.net实现表单validation,我已经尝试了这里建议的每个解决方案,但最好的是迄今为止在aspsnippets.com上 。

我的代码如下:

      

使用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; }  

问题是电子邮件字段仅validation正则表达式。 如果我更改validation器的顺序,它只validation所需的表达式。

可能的问题是代码循环遍历所有validation器,但不会比较同时引用同一控件的validation器。 这会导致仅在控件上应用最后一个validation器条件。

可能的问题是代码循环遍历所有validation器,但不会比较同时引用同一控件的validation器。 这会导致仅在控件上应用最后一个validation器条件。

是的,这确实是问题所在。 要解决此问题,您可以执行以下操作:

WebForm_OnBlur函数中,循环通过与失去焦点的控件(而不是页面上的所有validation器)关联的validation器,并仅在所有validation器都有效时清除className属性:

 function WebForm_OnBlur(control) { for (var i = 0; i < control.Validators.length; i++) { if (!control.Validators[i].isvalid) { control.className = "error"; return; } } control.className = ""; } 

TextBox控件的onblur属性中, this作为参数传递给WebForm_OnBlur

   

WebForm_OnSubmit函数中,为具有关联validation器的每个控件调用WebForm_OnBlur

 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; } 

除了@MichaelLiu之外,您还可以创建自己的validation程序inheritance自CustomValidator类并更改validation程序的呈现,以使它们更容易使用。

例如:

Validators.cs


注意我们如何添加CssControlErrorClass的属性。 我们将在应用具有无效输入的类时使用它。

我们还设置了其他属性,因此您不必每次都设置它们, ClientValidationFunctionValidateEmptyText

 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; } } } 

Validators.js


由于在之前的类中我们预先定义了javascript函数,我们可以像这样添加一个简单的脚本:

 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; }, } 

非常简单的validation库,您可以轻松扩展您真正感兴趣的内容。

Default.aspx的


之后,您可以将控件放入页面:

   

这是最好的方法吗? 可能不是,(这两个使用Microsoft提供的默认实现)有比我更智能的人,我不使用WebForms。 我看到的最大好处是,您可以使用熟悉的语法获得一些可重用的代码,这些代码最终将包含您的所有validation需求,而不是每次都使用js来获取validation“规则”的方式。

通过替换下面的代码段解决了该问题。 要纠正我们必须遍历控件的所有validation器,然后我们应该决定是否必须标记错误类。 在此之后,您的代码将按预期工作。

更换循环

  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) { } } 

使用以下代码

  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) { } } 

我刚刚运行它,这是非常好的工作:)试试这个解决方案!

你可以在javascript中尝试Page_ClientValidate()而不是循环validation器。 我相信这将validation页面上的所有validation器。 如果要validation特定validation组绑定的特定控件,它还会使用“validation组名称”参数。