9

What property do I use on the required field validator control to make the textbox red if there is a validation error?

Here is my code:

<asp:Label ID="lblFirstName" runat="server" AssociatedControlID="txtFirstName" Text="First Name:" CssClass="reg-labels" />
<br />
<asp:TextBox ID="txtFirstName" runat="server" CausesValidation="true" MaxLength="60" CssClass="standard_width"/>
<asp:RequiredFieldValidator ControlToValidate="txtFirstName" runat="server" ID="valFirstName" ValidationGroup="grpRegistration" ErrorMessage="First Name is required." Text="*" />
Greg Finzer
  • 6,714
  • 21
  • 80
  • 125
  • You could use a [`ValidatorCalloutExtender`](http://www.asp.net/ajaxlibrary/ajaxcontroltoolkitsamplesite/validatorcallout/validatorcallout.aspx), it has a `HighlightCssClass` property for this. – Tim Schmelter Jan 20 '14 at 15:37
  • Basically there should be a .axd file rendered to handle all validation. All you need is check where they are displaying the error message and add the new generic class `highlight-error` – Murali Murugesan Jan 20 '14 at 15:55
  • Updated my answer with a working code – Murali Murugesan Jan 20 '14 at 17:13

5 Answers5

18

ASP.Net web forms internally uses a Javascript frameworka located at aspnet_client\{0}\{1} folder to handle the validation, etc. They are basically determined from the property ClientScriptsLocation

Try overriding the default framework function by keeping it in your page includes additional line to set the control_to_validate color

document.getElmentById(val.controltovalidate).style.border='1px solid red';

<asp:TextBox ID="txtFirstName" runat="server" CausesValidation="true" MaxLength="60"
    CssClass="standard_width" />
<asp:RequiredFieldValidator ControlToValidate="txtFirstName" runat="server" ID="valFirstName" ValidationGroup="grpRegistration" ErrorMessage="First Name is required." Text="*" />
<asp:Button Text="Super" ID="btnSubmit" CausesValidation="true" runat="server" />

JS

<script type="text/javascript">
    function ValidatorUpdateDisplay(val) {
        if (typeof (val.display) == "string") {
            if (val.display == "None") {
                return;
            }
            if (val.display == "Dynamic") {
                val.style.display = val.isvalid ? "none" : "inline";
                return;
            }

        }
        val.style.visibility = val.isvalid ? "hidden" : "visible";
        if (val.isvalid) {
            document.getElementById(val.controltovalidate).style.border = '1px solid #333';
        }
        else {
            document.getElementById(val.controltovalidate).style.border = '1px solid red';
        }          
    }
</script>
Murali Murugesan
  • 22,423
  • 17
  • 73
  • 120
  • 2
    From where to call ValidatorUpdateDisplay() function? – Dhaval Panchal Mar 06 '14 at 13:20
  • @DhavalPanchal you do not call it, Asp.Net does it for you. – Martin Braun Apr 27 '14 at 16:32
  • @Murali I tested the lower part of the script (from `val.style.visibility = ...` to end), because I only need the red border feature, without any displaying error text. This solution is a right approach, however it will not work when having multiple validators on one control, because the last validator-result will decide for the border or not absolutely, it will decline the red border maybe. Is there any way to show the red border when there is one "invalid" result of any validator on the control? I do not want to use a custom control that forces me for even more work for any form group. – Martin Braun Apr 27 '14 at 17:47
  • if i use two Validator for a control, its taking second validator and apply css based on second validator,not first one. I am using a Required Field Validator and Regular Expression Validator for a textbox, its showing as valid however i didn't enter value, showing as invalid only if second validator (Regular Expression Validator) fails. How to rectify ? Any solution? – Syed Mohamed Jul 18 '14 at 12:33
  • @Syed, check the viewsource of the page that may have some .axd file containing the javascript validation framework. Copy and rename it .js and include it in your page using script tag. It mean that now this script file is taking more priority than the .axd file included by asp.net. When you have the .js file, you can place a debugger and have a control of how it is executing. Debugging that will help you, where exactly you need to change. Its just a tip. – Murali Murugesan Jul 18 '14 at 15:25
  • @MuraliMurugesan I have copied this function in my asp.net page and the javascript function is not getting called. have i missed something? – Baahubali Jun 01 '17 at 02:14
  • How to works with that function with 2 forms in same page? – Shalom Dahan Dec 09 '18 at 17:13
  • @ShalomDahan, This answer was posted to old Asp.Net webforms 4.0, which has a support to only one form. If there are many forms, we can see the DOM structure in HTML and find out proper css selector – Murali Murugesan Dec 18 '18 at 14:36
  • @MuraliMurugesan I found solution with validation group – Shalom Dahan Dec 18 '18 at 19:26
13

Without overloading anything, give your <asp:*Validator tags a CssClass="garbage" attribute.

In your style sheet, create

.garbage {
    display: none;
}
.garbage[style*=visible] + input,
.garbage[style*=visible] + select,
.garbage[style*=visible] + textarea {
    background-color: #ffcccc;
    border: 1px solid #ff0000;
}

and any form control immediately preceded by a validator will be highlighted on invalid data.

EDIT:

I've seen a few methods for forcing a redraw in Chrome, including a pure css solution: transform: translateZ(0);

Patrick
  • 1,766
  • 1
  • 15
  • 27
  • This works perfectly, even with multiple validators. I just had to remove Display="Dynamic" from my validators. Simple and elegant. – Chris Olsen Apr 05 '15 at 14:17
  • 1
    If you want to use Display="Dynamic", simply change `.garbage[style*=visible]` to `.garbage[style*=inline]`. – Benjamin Ray Sep 11 '15 at 20:47
  • It doesn't seem to apply the style until I hover over or click on the textbox. Any ideas why? – GMon Oct 13 '15 at 15:31
  • I think that's to do with renderer optimisation. You can get around that by calling .hide() and .show() to force a refresh. – Patrick Oct 13 '15 at 15:38
  • 1
    This option is really nice! but remember to add the validator before the element you want to check. – Fabian Jul 08 '16 at 14:10
  • @Graham : HI Patrick, Graham, I am facing similar issue, but only on IE. On Chrome it is working fine. On IE, it applies the style only when the control is clicked. I am not sure I understood Patrick's comment about calling hide(), show(). Were you able to resolve the issue? – Milind Thakkar Nov 06 '16 at 11:16
  • I don't remember off the top of my head what that particular solution was, but it involved jQuery and an extra event handler somewhere. After the validator does its thing, you then make the control invisible and then visible again. It should be fast enough not to blink, but it will update the style. – Patrick Nov 07 '16 at 13:54
3

Murali's answer works great, but I rolled a jQuery version for myself if anyone's interested.

Based on the official documentation (https://msdn.microsoft.com/en-us/library/yb52a4x0.aspx), I was able to get each validator and check to see if it isvalid, and if not, use the errormessage property to populate my own notification system (setStatusMessage() is a function I wrote, feel free to use any other type of status message prompt, like alert() or roll your own).

/*
*   Validation Catcher - Sean D Kendle - 9/24/2015
*   Catch validation events and add to status messages system
*/
$(document).on("submit", function () {
    $.each(Page_Validators, function (i, v) {
        var strControlToValidateID = v.controltovalidate;
        var $controlToValidate = $("#" + strControlToValidateID);

        var arrInvalidControls = new Array(); //collection of all invalid field ids for later

        if (!v.isvalid) {
            $controlToValidate.addClass("error"); //custom error class, optional
            $controlToValidate.css("border-color", "#D00"); //manually set border-color per OP's question

            $(".error").eq(0).focus(); /*set focus to top-most invalid field on error, or you can use the v.focusOnError property to check if validator has this set (string "t" if true), but I don't want to have to set this every time*/

            arrInvalidControls.push(strControlToValidateID);  //collect all invalid field ids for later

            $(v).addClass("redtext"); //custom class - allows me to make all errors red without having to add a ForeColor property to every validator

            setStatusMessage(v.errormessage, "red", -1); // setStatusMessage is a function I wrote, replace with another alert system if desired, or delete this line
        } else {
            /*the following prevents control being seen as valid if there are two or more validators for the control - example:  required field validator, then custom or regex validator (first would be invalid, second would be valid for empty field)*/
            if (!$.inArray(strControlToValidateID, arrInvalidControls)) {
                $controlToValidate.removeClass("error");
                $controlToValidate.css("border-color", "");
            } else {
                //console.log(strControlToValidateID + " is already invalid.");
            }
        }
    });
});

I hope this helps someone!

Sean Kendle
  • 3,538
  • 1
  • 27
  • 34
1

Well, to your disappointment there isn't a direct way (cf https://stackoverflow.com/a/5249021/145682)

However, you can make use of a CustomValidator. Here is one way to define it:

<asp:TextBox ID="txtbx" runat="server"></asp:TextBox>
<asp:CustomValidator ID="customValidator" 
    runat="server" ValidationGroup="submit" ControlToValidate="txtbx" 
    ClientValidationFunction="foo" ErrorMessage="*"></asp:CustomValidator>

Make note of the ClientValidationFunction. It has to be written as follows:

    function foo(sender, e) {
        var value = e.Value;
        console.log('Value: ', e.Value);
        var ctrlid = sender.controltovalidate;
        var targetControl = document.getElementById(ctrlid);
        if (vowels.indexOf(value[0].toLowerCase()) == -1) {
            console.log('true-executed');
            e.isValid = false;
            targetControl.style.borderColor = 'red';
        }
        else {
            console.log('else-executed');
            e.isValid = true;
            targetControl.style.borderColor = '';
        }
    }

The controltovalidate property of sender will give you the id of the control you are looking for; in other words, your ControlToValidate. And, Value property of e should give you the target control's value.

The other option, is you can write your own server control to do the job: http://msdn.microsoft.com/en-us/library/aa719624(v=vs.71).aspx

Community
  • 1
  • 1
deostroll
  • 11,661
  • 21
  • 90
  • 161
  • 1
    But it requires every place you need to add ClientValidationFunction – Billa Jan 20 '14 at 17:15
  • @Billa yes you'd need to specify ClientValidationFunction for each CustomValidator you add. However, the js function it calls can be a single function which is written in such a way to handle validation logic as needed. The alternative is to create your own validation control. I've pointed to an msdn article which shows how to do so. – deostroll Jan 20 '14 at 18:47
1

Murali's answer worked for me as data changes, but on postback all the fields rendered as though there were no validation errors. I found that ASP.NET lazy-loads ValidatorUpdateDisplay, so the client-side override doesn't take effect until after it's already passed its onload validation. I'm guessing there's either a version or an implementation difference that blocked me here, but other solutions (including a few with CSS) weren't working either.

Eventually, I came upon a solution that combines Murali's answer with Dillie-O's solution from here: Change Text Box Color using Required Field Validator. No Extender Controls Please

<div class="pad-left">
  <asp:CompareValidator ID="comvIncTaxable" runat="server" ControlToValidate="tbIncTaxable" Display="Dynamic" Operator="DataTypeCheck" Type="Currency" CssClass="red-border"
     ErrorMessage="Please enter a currency value.">
     <span></span>
  </asp:CompareValidator>
  <asp:TextBox runat="server" ID="tbIncTaxable"></asp:TextBox>
</div>

<script type="text/javascript">
$(function () {
    setValidatedBordersOnLoad();
});
function ValidatorUpdateDisplay(val) {
    if (typeof (val.display) == "string") {
        if (val.display == "None") {
            return;
        }
        if (val.display == "Dynamic") {
            val.style.display = val.isvalid ? "none" : "inline";
            if (val.className == 'red-border' && val.controltovalidate) {
                if (val.isvalid) {
                    document.getElementById(val.controltovalidate).style.border = '1px solid #ccc';
                }
                else {
                    document.getElementById(val.controltovalidate).style.border = '1px solid red';
                }
            }
            return;
        }
    }
    val.style.visibility = val.isvalid ? "hidden" : "visible";
}

function setValidatedBordersOnLoad()
{
    for (var i = 0; i < Page_Validators.length; i++)
    {
        var val = Page_Validators[i];
        if (val.className == 'red-border' && val.controltovalidate) {
            var ctrl = document.getElementById(val.controltovalidate);
            if (ctrl != null && ctrl.style != null) {
                if (!val.isvalid)
                    ctrl.style.border = '1px solid red';
                else
                    ctrl.style.border = '1px solid #ccc';
            }
        }
    }
}
</script>

The nice thing about this solution is it lets you cherry-pick which validators get this special handling simply by adding CssClass='red-border' to the validator. In my case, I only wanted this behavior on fields within a specific grid where cell positioning shouldn't change, but still wanted to use out-of-box functionality elsewhere on the form.

Community
  • 1
  • 1
Kenbo
  • 131
  • 2
  • 9