Change Text Box Color using Required Field Validator. No Extender Controls Please

I need to change color of TextBox whenever its required field validator is fired on Clicking the Submit button


Solution 1:

What you can do is register a Javascript function that will iterate through the global Page_Validators array after submission and you can set the background appropriately. The nice thing about this is that you can use it on all of your controls on the page. The function looks like this:

function fnOnUpdateValidators()
{
   for (var i = 0; i < Page_Validators.length; i++)
   {
      var val = Page_Validators[i];
      var ctrl = document.getElementById(val.controltovalidate);
      if (ctrl != null && ctrl.style != null)
      {
         if (!val.isvalid)
            ctrl.style.background = '#FFAAAA';
         else
            ctrl.style.backgroundColor = '';
      }
   }
}

The final step is to register the script with the OnSubmit event:

VB.NET:

Page.ClientScript.RegisterOnSubmitStatement(Me.GetType, "val", "fnOnUpdateValidators();")

C#:

Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), "val", "fnOnUpdateValidators();");

You'll maintain the proper IsValid status in all of your code behind and it can work with all of your controls.

Note: I found this solution from the following blog. I just wanted to document it here in the event the source blog goes down.

Solution 2:

You can very easily override ASP.NET's javascript function that updates the display of validated fields. This is a nice option as you can keep your existing Field Validators, and don't have to write any custom validation logic or go looking for the fields to validate. In the example below I'm adding/removing an 'error' class from the parent element that has class 'control-group' (because I'm using twitter bootstrap css):

    /**
    * Re-assigns the ASP.NET validation JS function to
    * provide a more flexible approach
    */
    function UpgradeASPNETValidation() {
        if (typeof (Page_ClientValidate) != "undefined") {
            AspValidatorUpdateDisplay = ValidatorUpdateDisplay;
            ValidatorUpdateDisplay = NicerValidatorUpdateDisplay;
        }
    }

    /**
    * This function is called once for each Field Validator, passing in the 
    * Field Validator span, which has helpful properties 'isvalid' (bool) and
    * 'controltovalidate' (string = id of the input field to validate).
    */
    function NicerValidatorUpdateDisplay(val) {
        // Do the default asp.net display of validation errors (remove if you want)
        AspValidatorUpdateDisplay(val);

        // Add our custom display of validation errors
        if (val.isvalid) {
            // do whatever you want for invalid controls
            $('#' + val.controltovalidate).closest('.control-group').removeClass('error');
        } else {
            // reset invalid controls so they display as valid
            $('#' + val.controltovalidate).closest('.control-group').addClass('error');
        }
    }

    // Call UpgradeASPNETValidation after the page has loaded so that it 
    // runs after the standard ASP.NET scripts.
    $(document).ready(UpgradeASPNETValidation);

This is adapted ever-so-slightly from here and with helpful info from these articles.

Solution 3:

You could use CustomValidator instead of RequiredFieldValidator:

.ASPX

<asp:CustomValidator ID="CustomValidator1" runat="server" ErrorMessage=""
    ControlToValidate="TextBox1" ClientValidationFunction="ValidateTextBox"
    OnServerValidate="CustomValidator1_ServerValidate"
    ValidateEmptyText="True"></asp:CustomValidator>

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

<script src="jquery-1.2.6.js" type="text/javascript"></script>
<script type="text/javascript">
    function ValidateTextBox(source, args)
    {
        var is_valid = $("#TextBox1").val() != "";
        $("#TextBox1").css("background-color", is_valid ? "white" : "red");
        args.IsValid = is_valid;
    }
</script>

.CS

protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
    bool is_valid = TextBox1.Text != "";
    TextBox1.BackColor = is_valid ? Color.White : Color.Red;
    args.IsValid = is_valid;
}

Logic in client and server validation functions is the same, but the client function uses jQuery to access textbox value and modify its background color.

Solution 4:

Very late to the party, but just in case someone else stumbles across this and wants a complete answer which works with Bootstrap, I've taken all the examples above, and made a version which will work with multiple validators attached to a single control, and will work with validation groups:

<script>
    /**
    * Re-assigns the ASP.NET validation JS function to
    * provide a more flexible approach
    */
    function UpgradeASPNETValidation() {
        if (typeof (Page_ClientValidate) != "undefined") {
            AspValidatorUpdateDisplay = ValidatorUpdateDisplay;
            ValidatorUpdateDisplay = NicerValidatorUpdateDisplay;
            AspValidatorValidate = ValidatorValidate;
            ValidatorValidate = NicerValidatorValidate;

            // Remove the error class on each control group before validating
            // Store a reference to the ClientValidate function
            var origValidate = Page_ClientValidate;
            // Override with our custom version
            Page_ClientValidate = function (validationGroup) {
                // Clear all the validation classes for this validation group
                for (var i = 0; i < Page_Validators.length; i++) {
                    if ((typeof(Page_Validators[i].validationGroup) == 'undefined' && !validationGroup) ||
                        Page_Validators[i].validationGroup == validationGroup) {
                        $("#" + Page_Validators[i].controltovalidate).parents('.form-group').each(function () {
                            $(this).removeClass('has-error');
                        });
                    }
                }
                // Call the original function
                origValidate(validationGroup);
            };
        }
    }

    /**
    * This function is called once for each Field Validator, passing in the 
    * Field Validator span, which has helpful properties 'isvalid' (bool) and
    * 'controltovalidate' (string = id of the input field to validate).
    */
    function NicerValidatorUpdateDisplay(val) {
        // Do the default asp.net display of validation errors (remove if you want)
        AspValidatorUpdateDisplay(val);

        // Add our custom display of validation errors
        // IF we should be paying any attention to this validator at all
        if ((typeof (val.enabled) == "undefined" || val.enabled != false) && IsValidationGroupMatch(val, AspValidatorValidating)) {
            if (!val.isvalid) {
                // Set css class for invalid controls
                var t = $('#' + val.controltovalidate).parents('.form-group:first');
                t.addClass('has-error');
            }
        }
    }

    function NicerValidatorValidate(val, validationGroup, event) {
        AspValidatorValidating = validationGroup;
        AspValidatorValidate(val, validationGroup, event);
    }

    // Call UpgradeASPNETValidation after the page has loaded so that it 
    // runs after the standard ASP.NET scripts.
    $(function () {
        UpgradeASPNETValidation();
    });
</script>

Solution 5:

I liked Rory's answer, but it doesn't work well with ValidationGroups, certainly in my instance where I have two validators on one field triggered by two different buttons.

The problem is that ValidatorValidate will mark the validator as 'isValid' if it is not in the current ValidationGroup, but our class-changing code does not pay any attention. This meant the the display was not correct (certainly IE9 seems to not like to play).

so to get around it I made the following changes:

    /**
    * Re-assigns the ASP.NET validation JS function to
    * provide a more flexible approach
    */
    function UpgradeASPNETValidation() {
        if (typeof (Page_ClientValidate) != "undefined") {
            AspValidatorUpdateDisplay = ValidatorUpdateDisplay;
            ValidatorUpdateDisplay = NicerValidatorUpdateDisplay;
            AspValidatorValidate = ValidatorValidate;
            ValidatorValidate = NicerValidatorValidate;
        }
    }

    /**
    * This function is called once for each Field Validator, passing in the 
    * Field Validator span, which has helpful properties 'isvalid' (bool) and
    * 'controltovalidate' (string = id of the input field to validate).
    */
    function NicerValidatorUpdateDisplay(val) {
        // Do the default asp.net display of validation errors (remove if you want)
        AspValidatorUpdateDisplay(val);

        // Add our custom display of validation errors
        // IF we should be paying any attention to this validator at all
        if ((typeof (val.enabled) == "undefined" || val.enabled != false) && IsValidationGroupMatch(val, AspValidatorValidating)) {
            if (val.isvalid) {
                // do whatever you want for invalid controls
                $('#' + val.controltovalidate).parents('.control-group:first').removeClass('error');
            } else {
                // reset invalid controls so they display as valid
                //$('#' + val.controltovalidate).parents('.control-group:first').addClass('error');
                var t = $('#' + val.controltovalidate).parents('.control-group:first');
                t.addClass('error');
            }
        }
    }

    function NicerValidatorValidate(val, validationGroup, event) {
        AspValidatorValidating = validationGroup;
        AspValidatorValidate(val, validationGroup, event);
    }

    // Call UpgradeASPNETValidation after the page has loaded so that it 
    // runs after the standard ASP.NET scripts.
    $(document).ready(UpgradeASPNETValidation);