views:

7038

answers:

6

I have run into this problem before but never quite solved it. I have a form with several validators and also a CustomValidator.

<asp:Label ID="lblMemberNum" runat="server" Text="Membership #:" CssClass="LabelMedium"  ></asp:Label>
<asp:TextBox ID="txtMemberNum" runat="server" CssClass="TextBox" ></asp:TextBox>
<asp:RequiredFieldValidator ID="rfvMemberNum" SetFocusOnError="True" runat="server"
    ControlToValidate="txtMemberNum" ErrorMessage="[ Membership # ] is required"
    CssClass="ValidationMessage" Display="Dynamic" >*</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revMemberNum"  Display="Dynamic" runat="server" 
    ControlToValidate="txtMemberNum" CssClass="ValidationMessage" 
    ErrorMessage="[ Membership # ] can only contain letters" 
    ValidationExpression="^([a-zA-Z\d]+)$" >*</asp:RegularExpressionValidator>
<asp:CustomValidator ID="cvMemberNum" runat="server" 
    CssClass="ValidationMessage" Display="Dynamic"
    ControlToValidate="txtMemberNum" ValidateEmptyText="false"
    OnServerValidate="cvMemberNum_Validate" 
    ErrorMessage="This membership number is already registered">*</asp:CustomValidator>

<asp:ValidationSummary ID="ValidationSummary1" runat="server" 
    CssClass="ValidationMessage" 
    ShowMessageBox="True" ShowSummary="False" />

and on the server side:

protected void cvMemberNum_Validate(object source, ServerValidateEventArgs args)
{
    try
    {
        args.IsValid  = (!CampaignRegistration.IsMemberRegistered(args.Value));
    }
    catch
    {
        args.IsValid = false;
    }
}

My problem is: The ValidationSummary never shows the message from CustomValidator. This question has been asked in several places, but I havent seen a satisfactory answer.

+2  A: 

Try using a ValidationGroup property across all your validators and the ValidationSummary.

EDIT: Another possibility could be the Server Validation Code

args.IsValid = (!CampaignRegistration.IsMemberRegistered(args.Value));

if CampaignRegistration.IsMemberRegistered(args.Value) is returning false, "!" is making it true and therefore making it valid. I think you should get rid of the "!" as follows:

args.IsValid = CampaignRegistration.IsMemberRegistered(args.Value);

UPDATE: In order for the ValidationSummary to display your custom validator message in a messagebox, you need to have ClientValidationFunction Code. If you need to display just the summary without a popup, this is not needed.

<asp:CustomValidator ID="cvMemberNum" runat="server" 
    CssClass="ValidationMessage" Display="Dynamic"
    ControlToValidate="txtMemberNum" ValidateEmptyText="false"
    OnServerValidate="cvMemberNum_Validate"
    ClientValidationFunction = "ClientValidate"  
    ErrorMessage="This membership number is already registered">*</asp:CustomValidator>
   //JavaScript Code.
   function ClientValidate(source, args)
   {         
      args.IsValid = false; //you need to add validation logic here
   }

MORE: If you don't want to do ClientSide Validation, try this trick to show the alert. Make this change to your CustomValidator ServerValidate method:

protected void cvMemberNum_Validate(object source, ServerValidateEventArgs args)
{
    bool isValid = true;
    try
    {
        isValid  = (!CampaignRegistration.IsMemberRegistered(args.Value));
    }
    catch
    {
        isValid = false;
    }
    args.IsValid = isValid;

    if(!isValid)
    {
       if(!Page.IsClientScriptBlockRegistered("CustomValidation")) 
         Page.RegisterClientScriptBlock("CustomValidation", "<script>alert('This membership number is already registered');</script>"); 

    }

}
Jose Basilio
I'm pretty sure that's not where the problem is. However, I'll try that and report back.
deverop
I updated my post after making an observation. Please confirm.
Jose Basilio
The code you highlighted is actually ok. Validation fails if the user is already registered. That part works. What happens is, the '*' appears next to the textbox, but the ValidationSummary does not render a messagebox.
deverop
If you want the validation summary to display as a message box you need to have EnableClientScript=true for your CustomValidator. Have you tried using ShowSummary instead, just to see if that works?
Jose Basilio
With ShowSummary, it works. However, I prefer to render a messagebox, and have to do it through the ValidationSummary. Can't use custom javascript.
deverop
This is the only way to make it display in a messagebox using the standard controls. However, you could try registering a client script in your ServerValidate method, to make the alert show up.
Jose Basilio
Thanks! I guess that leaves me no other choice. Thought there was a way to force it. I really appreciate your help.
deverop
+1  A: 

You should write a property

ValidationGroup="ValidationSummary1"

at every validator in your case.

Also check if your page has

AutoEventWireup="true"
DaDa
The CustomValidator actually validates and executes server side code. When invalid, it shows its text("*") next to the textbox. However, the ValidationSummary shows other messages but not from CustomValidator.
deverop
Just try this two instructions, and tell me. Because I have absolutely the same case, and the message from the custom validator shows up in the validationsummary
DaDa
Thanks for your response DaDa. Maybe I should clarify that the ValidationSummary shows error from CustomValidator IF I set ShowSummary="true". The problem is when I want to show a messagebox.
deverop
+5  A: 

The ShowMessageBox option is fully client-side, so it will only evaluate if you have set the ClientValidationFunction on the CustomValidator.

You can also fake it by registering a script that makes an alert, so when you get back from the server's validation, it'll prompt with the error message. This can either be registered in the ServerValidate method (per @Jose Basilio), or you can call the following method during the PreRender event to register a popup with all invalid validators on the page:

    /// <summary>
    /// Registers a script to display error messages from server-side validation as the specified <see cref="UserControl"/> or <see cref="Page"/> loads from a postback.
    /// </summary>
    /// <remarks>
    /// Must be called in the PreRender if used to validate against the Text property of DNNTextEditor controls, otherwise Text will not be populated.
    /// Must set the ErrorMessage manually if using a resourcekey, otherwise the resourcekey will not have overridden the ErrorMessage property.
    /// </remarks>
    /// <param name="ctrl">The <see cref="UserControl"/> or <see cref="Page"/> which is being posted back.</param>
    /// <param name="validationGroup">The validation group against which to validate.</param>
    public static void RegisterServerValidationMessageScript(TemplateControl ctrl, string validationGroup)
    {
        if (ctrl != null && ctrl.Page.IsPostBack)
        {
            ctrl.Page.Validate(validationGroup);
            if (!ctrl.Page.IsValid)
            {
                StringBuilder errorMessage = new StringBuilder("<script language='javascript'>alert('");
                for (int i = 0; i < ctrl.Page.Validators.Count; i++)
                {
                    IValidator validator = ctrl.Page.Validators[i];
                    if (!validator.IsValid)
                    {
                        errorMessage.Append("- " + validator.ErrorMessage);
                        if (i < ctrl.Page.Validators.Count - 1)
                        {
                            errorMessage.Append(@"\r\n");
                        }
                    }
                }

                errorMessage.Append("');</script>");
                ctrl.Page.ClientScript.RegisterStartupScript(typeof(IValidator), "validationAlert", errorMessage.ToString(), false);
            }
        }
    }
bdukes
Thanks A LOT! Works like a charm!
deverop
only problem is at the moment, I'm not allowed to render custom js.
deverop
A: 

This worked for me:

<asp:CustomValidator runat="server" ID="cv" 
ClientValidationFunction="ValidateFunction"
ErrorMessage="Default error
message">*</asp:CustomValidator>

<script type="text/javascript">
function ValidateFunction(sender, args) 
{

var msg ='';
var formValid = true;

[various checks setting msg and formValid]

if (msg.length > 0) { sender.errormessage = msg; }
args.IsValid = formValid;

}
</script>
mulmad
+1  A: 

I've recently had same problem. ValidationSummary was not showing the ErrorMessage from CustomValidator when ServerValidate stated validation failure. Since by default (as my little reverse engineering showed) validation summary is rendered client side on postback I've simply added a script that checks all validators on document load/async postback completion and triggers validation summary creation for failed validation groups:

$(document).ready(function () {
    var displayAlert = function () {
        if (typeof Page_Validators == 'undefined') return;

        var groups = [];
        for (i = 0; i < Page_Validators.length; i++)
            if (!Page_Validators[i].isvalid) {
                if (!groups[Page_Validators[i].validationGroup]) {
                    ValidationSummaryOnSubmit(Page_Validators[i].validationGroup);
                    groups[Page_Validators[i].validationGroup] = true;
                }
            }
    };

    displayAlert();

    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(
                    function () {
                        displayAlert();
                    });
}
);

In my scenario I had nested user controls with validators, update panel and validation summary at the parent page.

More details here.

smax
A: 

I have found a workaround for when javascript is disabled and the ValidationSummary does not show the errorMessage property of the CustomValidator. This is required as injecting script or alerts, as described above, will not work. Add a new Validator control, let's call it CustomValidatorProxy, set its ControlToValidate property to any one of the controls on the form and EnableClientScript=false. Within the ServerValidate event handler perform your custom validation and if validation fails set the IsValid property of the CustomValidator and CustomValidatorProxy to false and similarly set both ErrorMessage properties. If the validation in the ServerValidate is passed ensure that the IsValid property of the CustomValidatorProxy is set to true. Provided the CustomValidatorProxy is before the CustomValidator in the ValidatorCollection of the Page then the ServerValidate handler will override the IsValid property value that the CustomValidatorProxy would have returned having validated the ControlToValidate value and your ErrorMessage from your CustomValidator will be displayed in the ValidationSummary.