Home > Uncategorized > Creating AJAX Validator Control

Creating AJAX Validator Control

Imagine that you are creating a website registration form and you need to validate a Login ID or Email field. You want to make sure that the Login ID or Email entered does not already exist in the database. You could use the CustomValidator control to call a server-side function to check whether the field is unique in the database.

<asp:TextBox id="txtEmail" Runat="server" /> <asp:CustomValidator id="valEmail" ControlToValidate="txtEmail" Text="Email already exists" OnServerValidate="valEmail_ServerValidate" Runat="server" />
void valEmail_ServerValidate(Object source, ServerValidateEventArgs args) { if (EmailAlreadyExists(args.Value)) args.IsValid = false; else args.IsValid = true; }

This of course causes a postback to the server where the server-side function is executed and the page is refreshed. This can be frustrating to the user to have to enter all the fields and submit and the page refreshes only to find out that the Email address is already in the system.

To provide a better user experience we somehow need to call the server-side function from the client without causing a postback. Using AJAX (Asynchronous JavaScript and XML) we can create a validator control to call the server-side validation function from the client. The advantage of using AJAX is that no postback to the server is apparent to the user.

Our control needs to inherit from the BaseValidator class and also implement the ICallbackEventHandler interface. The BaseValidator class serves as the abstract base class for validation controls and provides the core implementation for all validation controls. The BaseValidator requires you to implement a single method:

  • EvaluateIsValid – returns true when the form field being validated is valid.

The BaseValidator class also includes several other methods that you can override or otherwise use. The most useful of these methods is the following:

  • GetControlValidationValue – enables you to retrieve the value of the control being validated.

When you create a custom validation control, you override the EvaluateIsValid() method and, within the EvaluateIsValid() method, you call GetControlValidationValue to get the value of the form field being validated.

public class MyAjaxValidator : BaseValidator, ICallbackEventHandler { public event ServerValidateEventHandler ServerValidate; string _controlToValidateValue; protected override bool EvaluateIsValid() { string controlToValidateValue = this.GetControlValidationValue(this.ControlToValidate); return ExecuteValidationFunction(controlToValidateValue); } private bool ExecuteValidationFunction(String controlToValidateValue) { ServerValidateEventArgs args = new ServerValidateEventArgs(controlToValidateValue, this.IsValid); if (ServerValidate != null) ServerValidate(this, args); return args.IsValid; }

The ICallbackEventHandler interface defines two methods that are called on the server when an AJAX request is made from the client:

  • RaiseCallbackEvent – called to handle the event, passing the event argument as a parameter
  • GetCallbackResult – returns the result of the callback
public void RaiseCallbackEvent(string eventArgument) { _controlToValidateValue = eventArgument; } public string GetCallbackResult() { return ExecuteValidationFunction(_controlToValidateValue).ToString(); }

In the OnPreRender() method, a JavaScript include file and startup script are registered.

protected override void OnPreRender(EventArgs e) { String eventRef = Page.ClientScript.GetCallbackEventReference(this, "", "", ""); String includeScript = Page.ResolveClientUrl("~/Scripts/MyAjaxValidator.js"); Page.ClientScript.RegisterClientScriptInclude("MyAjaxValidator", includeScript); String startupScript = String.Format(“document.getElementById('{0}').evaluationfunction = 'MyAjaxValidatorEvaluateIsValid';", this.ClientID); Page.ClientScript.RegisterStartupScript(this.GetType(), "MyAjaxValidator", startupScript, true); base.OnPreRender(e); } protected override bool DetermineRenderUplevel() { return Context.Request.Browser.SupportsCallback; }

The JavaScript include file contains the client-side functions that are called when the MyAjaxValidator validates a form field on the client. The startup script associates the client-side MyAjaxValidatorEvaluateIsValid() function with the MyAjaxValidator control. The client-side validation framework automatically calls this JavaScript function when performing validation.

function MyAjaxValidatorEvaluateIsValid(val) { var value = ValidatorGetValue(val.controltovalidate); WebForm_DoCallback(val.id, value, MyAjaxValidatorResult, val, MyAjaxValidatorError, true); return true; } function MyAjaxValidatorResult(returnValue, context) { if (returnValue == 'True') context.isvalid = true; else context.isvalid = false; ValidatorUpdateDisplay(context); } function MyAjaxValidatorError(message) { alert('Error: ' + message); }

The MyAjaxValidatorEvaluateIsValid() JavaScript method initiates an AJAX call by calling the WebForm_DoCallback() method. This method calls the server-side validation function associated with the MyAjaxValidator control. When the AJAX call completes, the MyAjaxValidatorResult() method is called. This method updates the display of the validation control on the client.

The following page illustrates how you can use the MyAjaxValidator control. This page handles the MyAjaxValidator control’s ServerValidate event to associate a custom validation function with the control. The validation function checks whether a email already exists in the database. If you enter a email that already exists, a validation error message is displayed. The message is displayed in the browser before you submit the form back to the server.

<form id="form1" runat="server"> <asp:Label id="lbEmail" Text="Email:" AssociatedControlID="txtEmail" Runat="server" /> <asp:TextBox id="txtEmail" Runat="server" /> <custom:MyAjaxValidator id="valEmail" ControlToValidate="txtEmial" Text="Email already exists" OnServerValidate="valEmail_ServerValidate" Runat="server" /> <br /> <!--some other controls here --> <br /> <asp:Button id="btnSubmit" Text="Submit" Runat="server" OnClick="btnSubmit_Click" /> </form>

And in code behind

protected void valEmail_ServerValidate(object source, ServerValidateEventArgs args) { if (EmailAlreadyExists(args.Value)) args.IsValid = false; else args.IsValid = true; }

It is important to realize that you can associate any server-side validation function with the MyAjaxValidator. You can perform a database lookup, call a web service, or perform a complex mathematical function. Whatever function you define on the server is automatically called on the client.

Complete code for MyAjaxValidator:

public class MyAjaxValidator : BaseValidator, ICallbackEventHandler { public event ServerValidateEventHandler ServerValidate; string _controlToValidateValue; protected override bool EvaluateIsValid() { string controlToValidateValue = this.GetControlValidationValue(this.ControlToValidate); return ExecuteValidationFunction(controlToValidateValue); } protected override void OnPreRender(EventArgs e) { String eventRef = Page.ClientScript.GetCallbackEventReference(this, "", "", ""); String includeScript = Page.ResolveClientUrl("~/Scripts/MyAjaxValidator.js"); Page.ClientScript.RegisterClientScriptInclude("MyAjaxValidator", includeScript); String startupScript = String.Format(“document.getElementById('{0}').evaluationfunction = 'MyAjaxValidatorEvaluateIsValid';", this.ClientID); Page.ClientScript.RegisterStartupScript(this.GetType(), "MyAjaxValidator", startupScript, true); base.OnPreRender(e); } protected override bool DetermineRenderUplevel() { return Context.Request.Browser.SupportsCallback; } public void RaiseCallbackEvent(string eventArgument) { _controlToValidateValue = eventArgument; } public string GetCallbackResult() { return ExecuteValidationFunction(_controlToValidateValue).ToString(); } private bool ExecuteValidationFunction(String controlToValidateValue) { ServerValidateEventArgs args = new ServerValidateEventArgs(controlToValidateValue, this.IsValid); if (ServerValidate != null) ServerValidate(this, args); return args.IsValid; } }
 
REF:
Sams ASP.Net 2.0 by Stephen Walther
 

Tags: , ,
  1. Lukas
    May 27, 2008 at 12:29 pm

    Hi there, Great article and very informative. I only have one problem with this. I cannot get it to work with master pages. I\’ve searched the internet and found solutions but none describes it in enough detail for me to fix it. Seems like  the WebForm DoCallback() requires the Unique ID not the ClientID to be passed to it as written in this post. Unfortunately this is not working for me. Whenever I pass the unique id it returns the control name with \’$\’ instead of \’:\’ as they say it should. Could you please explain to me what needs to be changed in your code for the validator to work in Master pages. I am using .net 3.5 and vs 2008. Thanks a lot in advanceLukas

  2. Misbah
    May 27, 2008 at 9:06 pm

    Lukas,
    Thank you for pointing out the master page issue. You can make this validator work with master pages by changing the MyAjaxValidatorEvaluateIsValid function in the javacsript file to:
     
        var callbackId = val.id;    callbackId = callbackId.replace(/_/g, "$");    WebForm_DoCallback(callbackId, value, MyAjaxValidatorResult, val, MyAjaxValidatorError, true);
     
    OR to make this control work with or without master pages modify the PreRender to and create a seperate javascript function which does the replace to get the uniqueid:
     
    //PreRender
    String startupScript = String.Format("document.getElementById(\’{0}\’).evaluationfunction = \’MyAjaxValidatorEvaluateIsValid\’;", this.ClientID);if(Page.Master != null)  startupScript = String.Format("document.getElementById(\’{0}\’).evaluationfunction = \’MyAjaxValidatorMasterPageEvaluateIsValid\’;", this.ClientID);Page.ClientScript.RegisterStartupScript(this.GetType(), "MyAjaxValidator", startupScript, true);
     
    //javascript

    function \’MyAjaxValidatorMasterPageEvaluateIsValid\'(val){    var value = ValidatorGetValue(val.controltovalidate);    var callbackId = val.id;    callbackId = callbackId.replace(/_/g, "$");    WebForm_DoCallback(callbackId, value, MyAjaxValidatorResult, val, MyAjaxValidatorError, true);
        return true;}

  3. Micah Dion(张卖卡)
    December 16, 2008 at 11:00 am

    Your article gives me great help, thank you very much. But here I\’ve found a bug.In the method "MyAjaxValidatorEvaluateIsValid" it returns "true" immediatelly after call the callback function. So when the page is being submited, validator scripts makes mistake.But still now, I have no idea to fix it, even though I use the synchronize callback function, the "MyAjaxValidatorEvaluateIsValid" returns without waiting…mmmmm…. Do you have any advice?Thanks again.By the way…My English is very weak…I can hardly to express, hope you can understand me, sorry.

  4. Unknown
    May 15, 2009 at 4:50 pm

    Hi,Great blog with interesting informations. I can use it t solve my problem.ThanxM.

  5. Ashish
    August 13, 2009 at 5:49 pm

    Seems like very nice article .but when i am trying to use it i am getting the js error as object expected. and on debugging i find out the error was coming when executing the function WebForm_DoCallback. i dont understand why WebForm_DoCallback is not getting rendered when the page is executed..any help from you guys will great for me.thanks

  1. No trackbacks yet.

Leave a reply to Unknown Cancel reply