21

How can I execute some javascript when a Required Field Validator attached to a textbox fails client-side validation? What I am trying to do is change the css class of the textbox, to make the textbox's border show red.

I am using webforms and I do have the jquery library available to me.

6 Answers 6

25

Here is quick and dirty thing (but it works!)

<form id="form1" runat="server">
      <asp:TextBox ID="txtOne" runat="server" />
      <asp:RequiredFieldValidator ID="rfv" runat="server" 
                                 ControlToValidate="txtOne" Text="SomeText 1" />
      <asp:TextBox ID="txtTwo" runat="server" />
      <asp:RequiredFieldValidator ID="rfv2" runat="server" 
                                 ControlToValidate="txtTwo" Text="SomeText 2" />
      <asp:Button ID="btnOne" runat="server" OnClientClick="return BtnClick();" 
                                         Text="Click" CausesValidation="true" />
    </form>
    <script type="text/javascript">
        function BtnClick() {
            //var v1 = "#<%= rfv.ClientID %>";
            //var v2 = "#<%= rfv2.ClientID %>";
            var val = Page_ClientValidate();
            if (!val) {
                var i = 0;
                for (; i < Page_Validators.length; i++) {
                    if (!Page_Validators[i].isvalid) {
                        $("#" + Page_Validators[i].controltovalidate)
                         .css("background-color", "red");
                    }
                }
            }            
            return val;
        }
    </script>
Sign up to request clarification or add additional context in comments.

6 Comments

I think your v1 and v2 variables are unused :P
yep, but this is quick and dirty :D. just commented them.
maybe dirty, but I haven't found a better solution !! :P
What is the reason to write the var i = 0 statement outside of the for loop?
Because the only variable scope delimiter in js is the function. So declaring it inside the for declaration is misleading.
|
21

You could use the following script:

<script>

    $(function(){
        if (typeof ValidatorUpdateDisplay != 'undefined') {
            var originalValidatorUpdateDisplay = ValidatorUpdateDisplay;

            ValidatorUpdateDisplay = function (val) {
                if (!val.isvalid) {
                    $("#" + val.controltovalidate).css("border", "2px solid red");
                }

                originalValidatorUpdateDisplay(val);
            }
        }
    });

</script>

This code decorates the original ValidatorUpdateDisplay function responsible for updating the display of your validators, updating the controltovalidate as necessary.

Hope this helps,

2 Comments

To enable easier custom styling, you can do: $("#" + val.controltovalidate).toggleClass('error', !val.isvalid);
+1 saved me some Google time here, thank you gsimoes and @GrimaceofDespair
2

I think you would want to use a Custom Validator and then use the ClientValidationFunction... Unless it helpfully adds a css class upon fail.

1 Comment

Important notice: this won't work for trying to check whether a field is empty or not; the CustomValidator isn't triggered if the field to check is empty. :-(
0

Some time ago I spend a few hours on it and since then I have been using some custom js magic to accomplish this.

In fact is quite simple and in the way that ASP.NET validation works. The basic idea is add a css class to attach a javascript event on each control you want quick visual feedback.

<script type="text/javascript" language="javascript">
    /* Color ASP NET validation */
    function validateColor(obj) {
         var valid = obj.Validators;
         var isValid = true;

         for (i in valid)
              if (!valid[i].isvalid)
                  isValid = false;

         if (!isValid)
             $(obj).addClass('novalid', 1000);
         else
             $(obj).removeClass('novalid', 1000);
    }

    $(document).ready(function() {
        $(".validateColor").change(function() {validateColor(this);});
    });
</script>

For instance, that will be the code to add on an ASP.Net textbox control. Yes, you can put as many as you want and it will only imply add a CssClass value.

<asp:TextBox ID="txtBxEmail" runat="server" CssClass="validateColor" />

What it does is trigger ASP.Net client side validation when there is a change on working control and apply a css class if it's not valid. So to customize visualization you can rely on css.

.novalid {
    border: 2px solid #D00000;
}

It's not perfect but almost :) and at least your code won't suffer from extra stuff. And the best, works with all kind of Asp.Net validators, event custom ones.

I haven't seen something like this googling so I wan't to share my trick with you. Hope it helps.

extra stuff on server side:

After some time using this I also add this ".novalid" css class from code behind when need some particular validation on things that perhaps could be only checked on server side this way:

Page.Validate();
    if (!requiredFecha.IsValid || !CustomValidateFecha.IsValid)
        txtFecha.CssClass = "validateColor novalid";
    else
        txtFecha.CssClass = "validateColor";

4 Comments

What if user doesnt input anything and posts the page. This code won't validate on submit...
@HasanG&#252;rsoy I wrote this long time ago but the idea was mainly to add some behavior on standard ASP.net controls. I guess you can add some onClick behavior over any submit elements to trigger calling the function as well.
Hmm yes, thank you. But I guess it will cause the same bug as I asked here: stackoverflow.com/questions/24477219/…
@HasanGürsoy sure as you then will need a custom validator probably
0

Here is my solution.

Advantages over other solutions:

  • Integrates seamlessly with ASP.NET - NO changes required to code. Just call the method on page load in a master page.
  • Automatically changes the CSS class when the text box or control changes

Disadvantages:

  • Uses some internal features of ASP.NET JavaScript code
  • Tested only on ASP.NET 4.0

HOW TO USE:

  • Requires JQuery
  • Call the "Validation_Load" function when the page loads
  • Declare a "control_validation_error" CSS class

    function Validation_Load() {
    if (typeof (Page_Validators) != "object") {
        return;
    }
    
    for (var i = 0; i < Page_Validators.length; i++) {
        var val = Page_Validators[i];
        var control = $("#" + val.controltovalidate);
        if (control.length > 0) {
            var tagName = control[0].tagName;
            if (tagName != "INPUT" && tagName != "TEXTAREA" && tagName != "SELECT") {
                // Validate sub controls
            }
            else {
                // Validate the control
                control.change(function () {
                    var validators = this.Validators;
                    if (typeof (validators) == "object") {
                        var isvalid = true;
                        for (var k = 0; k < validators.length; k++) {
                            var val = validators[k];
                            if (val.isvalid != true) {
                                isvalid = false;
                                break;
                            }
                        }
                        if (isvalid == true) {
                            // Clear the error
                            $(this).removeClass("control_validation_error");
                        }
                        else {
                            // Show the error
                            $(this).addClass("control_validation_error");
                        }
                    }
                });
            }
        }
    }
    }
    

Comments

-2

Alternatively, just iterate through the page controls as follows: (needs a using System.Collections.Generic reference)

const string CSSCLASS = " error";    

protected static Control FindControlIterative(Control root, string id)
{
   Control ctl = root;
   LinkedList<Control> ctls = new LinkedList<Control>();
   while ( ctl != null )
   {
     if ( ctl.ID == id ) return ctl;
     foreach ( Control child in ctl.Controls )
     {
       if ( child.ID == id ) return child;
       if ( child.HasControls() ) ctls.AddLast(child);
     }
     ctl = ctls.First.Value;
     ctls.Remove(ctl);
   }
   return null;
}



protected void Page_PreRender(object sender, EventArgs e)
{
  //Add css classes to invalid items
  if ( Page.IsPostBack && !Page.IsValid )
  {
    foreach ( BaseValidator item in Page.Validators )
    {
       var ctrltoVal = (WebControl)FindControlIterative(Page.Form, item.ControlToValidate);
       if ( !item.IsValid ) ctrltoVal.CssClass += " N";
       else ctrltoVal.CssClass.Replace(" N", "");
    }
  }
}

Should work for most cases, and means you dont have to update it when you add validators. Ive added this code into a cstom Pageclass so it runs site wide on any page I have added validators to.

1 Comment

Its very inefficient to iterate through every control on a page, I don't think you should do this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.