Jason
Jason

Reputation: 52547

jQuery and ASP.NET Custom Validator

I'm trying to learn jQuery and it occurred to me that existing JS in some of my sites could be replaced with just a few lines of jQuery code. In the following code, I'm trying to set the value of a custom validator by making an AJAX call. The first block of code does not work as it should, whereas the second block works fine. The whole "if it ain't broke don't fix it" answer isn't helpful, I really want to learn jQuery. For the record, I've placed alerts in the code and they both return the exact same result, just one is setting the args and the other is not for some reason.

Why does this code NOT work:

    function CheckForUserName(sender, args)
{
    args.IsValid = true;

    var url = "/somepage.aspx";

    MakeCall(url, function(txt) {
    if (txt == "false") {
        args.IsValid = false;
    }
    });
}

function MakeCall(url,callback) { 
    $.ajax({
        url: url,
        dataType: "text",
        success: callback
    });
}

This code DOES work:

    function CheckForUserName(sender, args)
{
        args.IsValid = true;

        var call = MakeCall();
        if (call == "false")
        {
            args.IsValid = false;
        }

}

function MakeCall()
{ 
    var xmlHttp;
    var validation=true;

    xmlHttp=GetXmlHttpObject();
    if (xmlHttp==null)
    {
        alert ("Your browser does not support AJAX!");
        return;
    } 

    var url="/somepage.aspx";
    xmlHttp.onreadystatechange=function () 
    {
        if (xmlHttp.readyState==4)
        { 
            if (xmlHttp.status==200)
            {
                return xmlHttp.responseText;
            }
            else
            {
                alert(xmlHttp.status);
            }
        }
    };
    xmlHttp.open("GET",url,false);
    xmlHttp.send(null);
    return xmlHttp.responseText;
}

function GetXmlHttpObject()
{
var xmlHttp=null;
try
  {
  // Firefox, Opera 8.0+, Safari
  xmlHttp=new XMLHttpRequest();
  }
catch (e)
  {
  // Internet Explorer
  try
    {
    xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
    }
  catch (e)
    {
    xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
return xmlHttp;
}

Upvotes: 0

Views: 4000

Answers (3)

user1778770
user1778770

Reputation: 1570

Just for the record. Having a custom validator that allows AJAX calls is possible, but is a litle complicated. Here is an article about the issue.

Basically, one must do these things:

  1. Say "Invalid!" immediately.
  2. Show a "processing..." message instead of your "invalid" message.
  3. Start your long-runing process, AKA your AJAX request.
  4. As soon as your request ends, replace the ClientValidationFunction for a dummy function.
  5. Reset the original message.
  6. Update the validation state.
  7. Reset the original validation function but only when the validated control changes.

Here is the final function that accomplishes the task (taken from the article):

//Create our respond functions...
var Respond_True = function (sender, args) { args.IsValid = true; };
var Respond_False = function (sender, args) { args.IsValid = false; };

function AjaxValidator(sender, args, ajaxSettings){
    args.IsValid = false;

    //This is a reference to our validator control
    var $sender = $(sender);

    //Save the original message, color and validation function to restore them later.
    var originalMessage = $sender.text();
    var originalColor = $sender.css("color");
    var originalFunction = sender.clientvalidationfunction;
    var validatedControl = $("#" + sender.controltovalidate);

    //Change the error message for a friendlier one.
    $sender.text("Checking...").css({ color: "black" });

    var setRespondFunction = function (respondFunction) {
        sender.clientvalidationfunction = respondFunction;

        //Reconstitute original styles.
        $sender.text(originalMessage).css({ color: originalColor });

        //Re-validate our control
        ValidatorValidate(sender, null, null);
        ValidatorUpdateIsValid();

        var onChange = function(){
            //Reset the original validation function
            sender.clientvalidationfunction = originalFunction;
            //Re-validate to ensure the original validation function gets called
            ValidatorValidate(sender, null, null);
            ValidatorUpdateIsValid();
            //Ensure the validation function is called just once.
            validatedControl.unbind("change", onChange);
        };
        validatedControl.on("change", onChange);
    }

    var originalSuccessFunction = ajaxSettings.success;
    //Start the AJAX call..
    $.ajax($.extend(ajaxSettings, {
        success: function(data){
            setRespondFunction(originalSuccessFunction(data) ? "Respond_True" : "Respond_False");
        }
    }));
}

And here is a sample usage:

function MyJavascriptValidationFunctionName(sender, args){
    AjaxValidator(sender, args, {
        url: ...,
        type: ...,
        data: ...,
        success: function(data){
            return /*True or false*/;
        }
    });
}

Upvotes: 0

Marc M
Marc M

Reputation:

This works fyi.. ignore my custom javascript namespace functions, but you should get the concept.

<script type="text/javascript">
        function VerifyCustomerNumber(s, a) {
            var r = ProcessCustomerNumber(a.Value);
            a.IsValid = r;
        }
        function ProcessCustomerNumber(n) {
            var u = '/Services/WebServices/Customer.asmx/CountByCustomerNumber';
            var d = '{"Number": "' + n + '"}';
            $j.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: u,
                cache: false,
                async: false,
                data: d,
                dataType: "json",
                success: function(r) {
                    var v = Data.JS.Ajax.ParseJSON(r);
                    return v;
                }
            });
        }
    </script>

Upvotes: 0

Jose Basilio
Jose Basilio

Reputation: 51548

In order to make it work, you need to specify the async option as false:

function MakeCall(url,callback) { 
    $.ajax({
        async: false,
        url: url,
        dataType: "text",
        success: callback
    });
}

Upvotes: 2

Related Questions