How to add a 'submitHandler' function when using jQuery Unobtrusive Validation?
Asked Answered
B

5

50

I'm validating a form using the new unobtrusive validation features in ASP.NET MVC 3.

So there is no code that I have written to setup jQuery validate to start validating my form. Its all done by loading the jQuery.validate.unobtrusive.js library.

Unfortunately I need to whack in a 'are you sure?' message box when the form is valid but before submitting. With jQuery validate you would add the option handleSubmit when initialising like so:

$("#my_form").validate({
  rules: {
    field1: "required",
    field1: {email: true },
    field2: "required"
  },
  submitHandler: function(form) {
     if(confirm('Are you sure?')) {
       form.submit();
     }
  }
});

But you don't need to initialise when using the unobtrusive library.

Any ideas where/how I can add a submit handler in that case?

Thx

Burrows answered 20/1, 2011 at 12:18 Comment(3)
anybody: is there any official documentation for this from MS ?Betaine
note: the handleSubmit() is called only if all form values validate. It is not called if you have any errors. It's perfect for asking for confirmation like you are (because you know everything is valid) but if you want special handling when there are errors you must use invalidHandler - see DGreen's answerBetaine
Rather than waiting until it's already initialized, you can also call jQuery.validator.setDefaults directly and any subsequent form intializations will use those settings. Just make sure it runs before the DOM is loaded and jQuery Validator automatically initializes the forms.Anthozoan
T
79

The unobtrusive library will attach the validator on all forms, so you have to replace the submitHandler this way:

$("form").data("validator").settings.submitHandler = function (form) { alert('submit'); form.submit(); };
Truckle answered 21/1, 2011 at 22:22 Comment(7)
Thanks @Truckle - nice simple answer that has also increased my understanding of jQuery.Burrows
For dynamically loaded forms (ex. dialog), you must first call $.validator.unobtrusive.parse($('form')) or $('form').data will return undefined.Putter
Frustrating part about this is that i was stuck trying to figure out what was going wrong because if the submitHandler was set in <script> tags at the end of the document it works fine. but as soon as you put it in the document ready it will not work.Goerke
I tried all of the above to handle the invalidHandler popping an alert, but it doesn't pop up. And $('form').data('validator') returns undefined, even after I tried calling $.validator.unobtrusive.parse($('form')) as @Putter suggested.Sensorimotor
I've added this new question.Sensorimotor
NB Two caveats with this. (1) If using AJAX forms it will not work (see here: $(theForm).trigger("sumbit")). (2) need to avoid calling submit on the jQuery wrapper: it will just call validation and the handler. Of course #1 causes #2! Only way seems to be explicitly setting submitHandler to null the first time around.Porch
Also, I use .validate() function to obtain the validator object instead of .data("validator") in case the library changes its implementation. So my code would be: $("form").validate().settings.submitHandler = function..Coliseum
F
68

I found this question while looking for a way to set the invalidHandler, as opposed to the submitHandler. Interestingly, you can't set invalidHandler in the same way when using unobtrusive validation.

The function is not fired when an invalid form is detected:

$("form").data("validator").settings.invalidHandler = function (form, validator) {
    alert('invalid!');
};

This approach works:

$("form").bind("invalid-form.validate", function () {
  alert('invalid!');
});

It seems to be due to the way that the jquery.validate.unobtrusive.js script initialises the Validate plugin, and the way that the plugin invokes the handler.

Falk answered 25/1, 2011 at 22:46 Comment(4)
Note: the 'bind' approach here is literally the same exact way the jquery.validate init function does itBetaine
helps, who can help explain? it looks not a 'official' way, how if I want to define submitHandler?Magen
I tried all of the above to handle the invalidHandler popping an alert, but it doesn't pop up. And $('form').data('validator') returns undefined.Sensorimotor
I've added this new question.Sensorimotor
B
38

The following findings may be of interest to understand the difference between :

submitHandler : Called when the form is validated successfully - right before the server postback
invalidHandler : Called if validation fails and there is no post back

@DGreen's solution definitely seems to be the best way to inject special handling if the form validation fails and you need to do something such as display a pop-up validation summary (invalidHandler)

$("form").bind("invalid-form.validate", function () {
  alert('invalid!');
});

@PeteHaus solution is the best way to do something if you want to prevent postback of a successfully validated form (submitHandler)

$("form").data("validator").settings.submitHandler = function (form) { 
                                                     alert('submit'); form.submit(); };

However I was slightly concerned about what behavior I was overriding (or not overriding) by binding to the .validate method like this - and why I had to do each way differently. So I checked the source. I strongly recommend anybody who wants to understand this procedure more does so too - put in some 'alert' statements or 'debugger' statements and it's pretty easy to follow along*

Anyway it turns out that when the jquery.validate.unobtrusive handler initializes jquery.validate plugin it does so in the parseElement() method by retrieving options created by the validationInfo() method.

ValidationInfo() returns the options like this:

 options: {  // options structure passed to jQuery Validate's validate() method
             errorClass: "input-validation-error",
             errorElement: "span",
             errorPlacement: $.proxy(onError, form),
             invalidHandler: $.proxy(onErrors, form),
             messages: {},
             rules: {},
             success: $.proxy(onSuccess, form)
           },

The onErrors() method in jquery.validate.unobtrusive is responsible for dynamically creating the validation summary panel for MVC. If you're not creating a validation summary panel (with @Html.ValidationSummary() which must incidentally be contained within the FORM body) then this method is completely inert and does nothing so you don't need to worry.

function onErrors(event, validator) {  // 'this' is the form elementz
    var container = $(this).find("[data-valmsg-summary=true]"),
        list = container.find("ul");

    if (list && list.length && validator.errorList.length) {
        list.empty();
        container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

        $.each(validator.errorList, function () {
            $("<li />").html(this.message).appendTo(list);
        });
    }
}

If you really want to you can unbind the jquery.validate.unobtrusive handler like this - but i wouldn't bother myself

 $("form").unbind("invalid-form.validate"); // unbind default MS handler

If you're wondering why this works

 $("form").data("validator").settings.submitHandler = ...

and this doesn't work

 $("form").data("validator").settings.invalidHandler = ...

it's because submitHandler is explicily called inside jquery.validate when validation is performed. Therefore it doesn't matter at what point it is set.

 validator.settings.submitHandler.call( validator, validator.currentForm );

but the invalidHandler is bound to an event during init() like this so if you set it in your own code it is too late

if (this.settings.invalidHandler)
    $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);

A little stepping through code makes for a lot of understanding sometimes! Hope this helps

*Make sure you don't have minification in bundles enabled.

Betaine answered 23/12, 2012 at 21:15 Comment(6)
Nice detailed explanation Simon especially compared to my vague answer :)Falk
@Falk my answers tend to be proportional to the amount of pain and time the problem has caused me - but without your answer it would have been a lot longer by the time I'd figured it out!Betaine
I tried all of the above to handle the invalidHandler popping an alert, but it doesn't pop up. And $('form').data('validator') returns undefined.Sensorimotor
It's probably changed a lot since this answer :-(Betaine
@Simon_Weaver, thanks for your response. I now see that it's actually working, but only if I try to submit the form. Is there an event that's raised when there are validation errors whatsoever, even when the validation errors were added by the server during a previous postback?Sensorimotor
@Betaine I've added this new question.Sensorimotor
T
12

I prefer to inject an event handler, so that it can be bound to... :)

//somewhere in your global scripts
$("form").data("validator").settings.submitHandler = function (form) {
    var ret = $(form).trigger('before-submit');
    if (ret !== false) form.submit();
};

This way, I can bind to it anywhere needed...

//in your view script(s)
$("form").bind("before-submit", function() {
    return confirm("Are you sure?");
});
Totem answered 30/6, 2012 at 5:59 Comment(0)
S
1

I based this on the original answer, which didn't work for me. I guess things have changed in jQuery.

As usual, take this code and add copious error checking :D I use similar code to prevent double-submits on our forms, and it works fine in IE8+ (as of mvc4 and jquery 1.8.x).

$("#myFormId").confirmAfterValidation();

// placed outside of a $(function(){ scope
jQuery.fn.confirmAfterValidation = function () {
    // do error checking first.  should be null if no handler already
    $(this).data('validator').settings.submitHandler = confirmValidForm;
};

function confirmValidForm(form) {
    var validator = $(this);
    var f = $(form);
    if (confirm("really really submit?")) {
        // unbind so our handler doesn't get called again, and submit
        f.unbind('submit').submit();
    }
        // return value is _ignored_ by jquery.validate, so we have to set
        // the flag on the validator itself, but it should cancel the submit
        // anyway if we have a submitHandler
        validator.cancelSubmit = true;
    }
}
Stealage answered 14/7, 2013 at 13:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.