Stop custom validator from firing on each keystroke
Asked Answered
A

2

9

I wrote a custom validator using MVC DataAnnotations and the jQuery unobtrusive javascript library. It's working great. The only problem I have now is that after the initial validation, if the user edit's the field, it's firing the validator on each keystroke. Since the validator hits a web service to validate the input, I'd prefer that it always just validate the input when the user moves off of the field or the form is submitted. Is there a way to change this behavior? Here's my code:

<script type="text/javascript">
    $.validator.addMethod("validate_zipcode", function (value, element) {
        if (value == null || value.length == 0) {
            return true;
        }

        var isValid = false;
        $.ajax({
            async: false,
            dataType: "json",
            url: "/api/iszipvalid/" + value,
            success: function (response) {
                isValid = response;
            }
        });

        return isValid;
    });

    $.validator.unobtrusive.adapters.addBool('zipcode', 'validate_zipcode');
</script>
Amatol answered 11/2, 2011 at 14:57 Comment(0)
O
10

I'm not positive this will work in conjunction with ASP.NET MVC (I'll whip up a test project later), but validate allows you to set defaults for all instances of validate like this:

$.validator.setDefaults({ onkeyup: false });

If you can add that line before MVC gets a handle on validate it might work, but it'll disable onkeyup for all fields in all forms (judging by your post, it seems like this would be ok).

Hope that helps.

Outdare answered 12/2, 2011 at 16:54 Comment(1)
I did this and it's still calling the validator method on every keypress (or backspace), but <i>not</i> when I tab out of the field! What else can I try?Stithy
F
3

You can cancel your ajax request before starting a new one. You code could look something like:

<script type="text/javascript">
  var request = null;

  $.validator.addMethod("validate_zipcode", function (value, element) {
    if (value == null || value.length == 0) {
        return true;
    }

    if (request != null) {  
      request.abort();
    }

    var isValid = false;
    request = $.ajax({
        async: false,
        dataType: "json",
        url: "/api/iszipvalid/" + value,
        success: function (response) {
            isValid = response;
        }
    });

    return isValid;
  });

  $.validator.unobtrusive.adapters.addBool('zipcode', 'validate_zipcode');
</script>

This is what the jquery UI autocomplete does if you look at the calls made using firebug.

Freemason answered 11/2, 2011 at 15:28 Comment(5)
Correct me if I'm mistaken, but that would just cancel the ajax request if one is already in progress, right? It will still attempt to validate on keyup instead of on the blur event but it will only make one call at a time?Amatol
Yes that's correct, as far as I'm aware there's no way to change the validation other than by keyup. It might be worth looking at the new Remote attribute which does the same thing as your custom validation, but this also works by cancelling the request.Freemason
I'd use the Remote attribute, but there's a lot of other custom logic that happens (setting other UI elements) based on the validation. I implemented this on another field as well (email address -- to be sure it doesn't already exist) but it hits the DB for it on every keystroke. There has to be a way to change the event to "blur" instead of "keyup"...Amatol
request.abort(); should be added for all ajax driven validation to prevent early results overwrite late triggers. But the global scope placement of the "request" variable should be avoided by enclosing the whole thing in an anonymous function.Lebkuchen
Just found the library overrides $.ajax to add "mode" attribute to abort all pending requests. Have a look at jquery validate source code.Lebkuchen

© 2022 - 2024 — McMap. All rights reserved.