views:

417

answers:

1

I'm running a validation on form data, such that when somebody hits the submit button it checks the form's contents first. A number of fields (could be zero, could be more than one, depending on the page) have things like unique codes which require checking with the server first. I'm running an asynchronous request to the server, which simply responds 'ok' or 'taken' for each field. If any of the fields have errors, the page doesn't submit.

On the one hand, this should be asynchronous: it should continue validating the rest of the form fields while that request is off processing, including firing off other requests. If the call is made synchronously, then it visibly slows down feedback on later fields.

On the other hand, I want to make sure all the validation requests have returned (or timed out) before responding yes or no to the validate() method, and either allowing the submit to proceed or not. So if there are two fields that need validating then the validate() method should fire off those two AJAX requests, process the rest of the fields, and then wait until those two requests have returned before finally returning.

I can probably achieve this with some ugly homebaked solution (probably involving an array of random ids representing the requests in progress or something), but before I do is there any built-in function, plugin or standard technique I should be using instead?


Clarification

What I think I need is to make the code wait for the result from one or more asynchronous requests before proceeding with a method. This isn't the same as a callback, because the result of the method depends on the result of the requests. It isn't the same as a synchronous request because there may be more than one of them.

I'm using this to check the form before submitting:

$("form").submit(function () {
    return validate($(this));
});

If the validate() method returns false, then the form doesn't submit. validate() hilights any fields that aren't accepted. For normal fields, validate() looks something like this (vastly simplified version, without the feedback):

function validate(form) {
    resetWarnings(form);
    var ok = true;

    //  required fields
    form.find("input.required").each(function () {
        var field = $(this);
        if (field.val() === "") {
            ok = false;
        }
        return this; // meaningless in this case but a good habit to keep
    });

    //  fields that matches a pattern
    form.find("input.pattern").each(function () {
        var field = $(this);
        var pattern = field.data("pattern");
        if (!field.val().match(pattern)) {
            ok = false;
        }
        return this;
    });

    //  various other rules for other sorts of field
    ...

    return ok;
}

For AJAX fields it's more like this:

    form.find("input.lookup").each(function () {
        var field = $(this);
        var url = field.data("lookup");
        $.ajax({
            url: url,
            data: { code: field.val() },
            success: function (result) {
                if (result === "taken") {
                    ok = false;
                }
            }
        }
    });

But of course, validate() has already finished before the success method is called. So if I can make it wait until the ajax has been completed (either success or error) before returning, I can get the right result and stop the form being submitted. And if I made the ajax synchronous, then the entire method stops until it's done, which is wrong.


Further thought

Given Javascript's threading model (which is to say none at all), is what I'm asking for technically impossible?

+1  A: 

If I understand you correctly, you are wanting to check that the values (1..*) entered in a form are unique, once the user hits the submit button before performing the post on the form. If that is the case, I would create a JSON array of fields and values and send it all at once - so you are only waiting for one response. This should be quite easy using the jQuery 'each' function and using jQuery ajax.

You can then check the single result before posting the form.

It probably goes without saying, but make sure you repeat the same validation serverside once you have posted to avoid race conditions with other users.

You could validate individual fields as the user completes the form, and store the result, but this would be signficantly more chatty (for scalability reasons you should consider bandwidth) and you expose yourself to a greater chance of failing server side validation.

Mike
It isn't a sequence of identical unique fields, but the possibility that more than one field on a form needs server-side checking - at different URLs, against different checks. In fact, the multiple bit isn't what's important - it's making the validate() method wait for an asynchronous result. The only reason I emphasise that there may be more than one field is so that making a single synchronous call isn't a valid answer.
Marcus Downing
See clarification.
Marcus Downing
I'm not sure what I'm asking for is possible. Validating the fields as the user completes the form may end up being the only way.
Marcus Downing