Issue with chaining Required Field and Regular Expression validators for Textbox controls

后端 未结 4 963
失恋的感觉
失恋的感觉 2021-01-19 10:55

I\'m trying to implement a form validation with ASP.net and I have tried every solution suggested here but the best one was on aspsnippets.com so far.

My code is lik

相关标签:
4条回答
  • 2021-01-19 11:16

    you can try Page_ClientValidate() in javascript instead of looping across validator. I believe this will validate all the validators on the page. It also takes in parameter which "Validation group name" if you want to validate specific controls bound by particular validation group.

    0 讨论(0)
  • 2021-01-19 11:40

    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.

    Yes, this is indeed the problem. To fix it, you can do the following:

    In the WebForm_OnBlur function, loop through the validators associated with the control that lost focus (rather than all the validators on the page), and clear the className property only if all the validators are valid:

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

    In the onblur attribute of the TextBox controls, pass this as the argument to WebForm_OnBlur:

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

    In the WebForm_OnSubmit function, call WebForm_OnBlur for each control that has associated validators:

    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;
    }
    
    0 讨论(0)
  • 2021-01-19 11:40

    The issue is resolved by replacing the code snippet below. To correct we must loop through all the validators for a control, then we should decide whether it has to marked with the error class. After this, your code will work as expected.

    Replace the loop

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

    with the below code

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

    I just ran it and this is working excellently :) Try this solution!

    0 讨论(0)
  • 2021-01-19 11:43

    In addition to @MichaelLiu, You can make your own validators that inherit from the CustomValidator class and alter the rendering of the validators to make them a little easier to work with.

    For example:

    Validators.cs


    Take notice of how we add a property of CssControlErrorClass. We will use this when applying a class with the invalid input in question.

    We also set other properties so you don't have to set them everytime, ClientValidationFunction and ValidateEmptyText.

    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


    Since in the previous classes we pre-defined the javascript functions, we can add a simple script like so:

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

    Very simple validation library that you can easily extend with things you are actually interesting in.

    Default.aspx


    After than you can put the controls into your page:

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

    Is this the best way? Probably not, (these two use the default implementation that is given by Microsoft) there are way smarter people out there than I and I don't work with WebForms much. The biggest benefit I see is that you get some reusable code, using a familiar syntax, that will eventually contain all your validation needs versus messing around with js everytime to get the validation "rules" how you want them.

    0 讨论(0)
提交回复
热议问题