将文本框控件的必填字段验证器和正则表达式验证器链接时出现问题

4
我正在尝试使用ASP.net实现表单验证,我尝试了每个建议这里的解决方案,但目前最好的解决方案在aspsnippets.com上。

我的代码如下:

<asp:TextBox ID="tTitle" runat="server" onblur="WebForm_OnBlur()"/>
<asp:RequiredFieldValidator runat="server" ControlToValidate="tTitle"/>

<asp:TextBox ID="tEMail" runat="server" onblur="WebForm_OnBlur()"/>
<asp:RequiredFieldValidator runat="server" ControlToValidate="tEMail"/>
<asp:RegularExpressionValidator runat="server" ControlToValidate="tEMail"
ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"/>

<asp:LinkButton ID="btnSubmit" runat="server" Text="Submit"/>

Javascript

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

问题在于电子邮件字段仅验证正则表达式。如果我更改验证器的顺序,则仅验证必需表达式。
可能的问题是,代码循环遍历所有验证器,但不会同时比较引用同一控件的验证器。这会导致仅应用于控件的最后一个验证器条件。

创建一个服务器端自定义验证器怎么样?我现在不太做Web表单开发了,但是我在2010年左右做过一些基于服务器的自定义验证器。这里有一个有用的链接:http://msdn.microsoft.com/en-us/library/f5db6z8k(v=vs.90).aspx 祝你好运! - qamar
在您的测试期间,您将输入什么值到“tEmail”字段? - user3624833
是的,创建一个自定义控件将解决这个问题@qamar。 - HasanG
你使用的是哪个 .net 版本? - Justin
为了改变无效控件的颜色,我们将覆盖内置的ASP.Net JavaScript方法WebForm_OnSubmit。请参阅链接。 - HasanG
显示剩余4条评论
4个回答

3
可能的问题是代码循环遍历所有验证器,但没有同时比较引用同一控件的验证器。这会导致在控件上只应用最后一个验证器条件。
是的,这确实是问题所在。为了解决这个问题,您可以执行以下操作:
WebForm_OnBlur函数中,循环遍历与失去焦点的控件相关联的验证器(而不是页面上的所有验证器),并仅在所有验证器均有效时清除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函数。
<asp:TextBox ID="tTitle" runat="server" onblur="WebForm_OnBlur(this)"/>
<asp:TextBox ID="tEMail" runat="server" onblur="WebForm_OnBlur(this)"/>

WebForm_OnSubmit函数中,对于每个具有关联验证器的控件调用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;
}

1
除了 @MichaelLiu之外,你可以创建继承自 CustomValidator 类的自定义验证器,并改变验证器的呈现方式,使其更易于使用。
例如:

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

非常简单的验证库,您可以轻松地通过您真正感兴趣的内容进行扩展。

Default.aspx


然后您可以将控件放入您的页面:

<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来调整验证“规则”。


1
问题可以通过替换下面的代码片段来解决。为了纠正问题,我们必须循环遍历控件的所有验证器,然后决定是否将其标记为错误类。在此之后,您的代码将按预期工作。
替换循环。
 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) { }
    }

我刚刚运行了它,这个解决方案非常出色 :) 试试这个解决方案吧!


-1
你可以尝试在JavaScript中使用Page_ClientValidate(),而不是循环遍历验证器。 我相信这将验证页面上的所有验证器。 它还可以接受参数,如果您想验证特定验证组绑定的特定控件,则可以指定“验证组名称”。

那么对于无效控件添加CSS类呢? - HasanG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接