jQuery Validate SubmitHandler with Ajax Submission

2019-03-07 04:22发布

问题:

On my view I want to submit the form to the controller using ajax. I have this:

@section scripts{
    @Scripts.Render("~/bundles/jqueryval")

    <script>
        $(document).ready(function() {

            // Mask
            $("#Teu_Rate").mask("####.##", { reverse: true });
            $("#Mcsap_Rate").mask("####.##", { reverse: true });

            // Submission
            var redirectUrl = '@Url.Action("Index", "tblPersonnels")';
            var settings = {};
            settings.baseUri = '@Request.ApplicationPath';
            var infoGetUrl = "";
            if (settings.baseUri === "/Scalehouse") {
                infoGetUrl = settings.baseUri + "/tblPersonnels/Create/";
            } else {
                infoGetUrl = settings.baseUri + "tblPersonnels/Create/";
            }

            // ajax portion
            $("form").validate({
                submitHandler: function(form) {
                    $.ajax({
                        url: infoGetUrl,
                        method: "POST",
                        data: $("form").serialize(),
                        beforeSend: disableCreateBtn(),
                        success: function() {
                            console.log("success");
                            toastr.options = {
                                positionClass: "toast-top-full-width",
                                onHidden: function() {
                                    window.location.href = redirectUrl;
                                },
                                timeOut: 3000
                            }
                            toastr.success("Personnel successfully created")
                        },
                        error: function(jqXHR, textStatus, errorThrown) {
                            toastr.options = {
                                positionClass: "toast-top-full-width",
                                onHidden: function() {
                                    enableCreateBtn();
                                },
                                timeOut: 3000
                            }
                            var status = capitalizeFirstLetter(textStatus);
                            var error = $.parseJSON(jqXHR.responseText);
                            console.log(error);
                        }
                    })
                }
            });

            function capitalizeFirstLetter(string) {
                return string.charAt(0).toUpperCase() + string.slice(1);
            }

            function disableCreateBtn() {
                $('#Personnel-Create-Btn').prop('disabled', true);
            }

            function enableCreateBtn() {
                $('#Personnel-Create-Btn').prop('disabled', false);
            }
        });
    </script>
}

When the request is done and completed successfully, I should be getting a message in my console and a toastr notification, but I am receiving neither and I'm not receiving any console errors, but the record that I am entering is being entered successfully, so that means that the form is being submitted through regular MVC conventions.

How do I make my ajax submission work?

Update

After commenting below with Sparky, I've changed my code to:

$("form").submit(function (t) {

    t.preventDefault();

        $.ajax({
            url: infoGetUrl,
            method: "POST",
            data: $("form").serialize(),
            beforeSend: disableCreateBtn(),
            success: function() {
                console.log("success");
                toastr.options = {
                    positionClass: "toast-top-full-width",
                    onHidden: function() {
                        window.location.href = redirectUrl;
                    },
                    timeOut: 3000
                }
                toastr.success("Personnel successfully created");
            },
            error: function(jqXHR, textStatus, errorThrown) {
                toastr.options = {
                    positionClass: "toast-top-full-width",
                    onHidden: function() {
                        enableCreateBtn();
                    },
                    timeOut: 3000
                }
                var status = capitalizeFirstLetter(textStatus);
                //var error = $.parseJSON(jqXHR.responseText);
                console.log(jqXHR);
            }
        });

    });

Now, if the form is empty.. and I hit the create button.. somehow the ajax is going into the success function while giving me my validation errors on certain fields that are required.. then redirected to another page as if the request was successful.. any ideas?

Update 2

I got it working by using this syntax:

$("form").data("validator").settings.submitHandler =
    function(form) {
        $.ajax({
            url: infoGetUrl,
            method: "POST",
            data: $("form").serialize(),
            beforeSend: disableCreateBtn(),
            success: function () {
                console.log("success");
                toastr.options = {
                    positionClass: "toast-top-full-width",
                    onHidden: function () {
                        window.location.href = redirectUrl;
                    },
                    timeOut: 3000
                }
                toastr.success("Personnel successfully created.");
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
                toastr.options = {
                    positionClass: "toast-top-full-width",
                    onHidden: function () {
                        enableCreateBtn();
                    },
                    timeOut: 3000
                }
                var status = capitalizeFirstLetter(textStatus);
                var error = $.parseJSON(jqXHR.responseText);
                console.log(error);

                var modelState = error.modelState;
                //console.log(modelState);
                $.each(modelState,
                    function (key, value) {
                        var id = "";
                        if (key === "$id") {
                            id = "#" + key.replace('$', '').substr(0, 1).toUpperCase() + key.substr(2);
                        } else {
                            //console.log(key);
                            var status = capitalizeFirstLetter(textStatus);
                            toastr.error(status + " - " + modelState[key]);
                        }
                        var input = $(id);
                        //console.log(id); // result is #id
                        if (input) { // if element exists
                            console.log(id);
                            input.addClass('input-validation-error');
                        }
                    });
            }
        });
    }

I don't know why, but it is working.. I'm interested in hearing why though

回答1:

I got it working and updated my question as to how.. but could you explain why this syntax works over the others?

Your .submit() handler is a bad idea because it's going to interfere with the way the jQuery Validate plugin handles the form's submit event. (Basically, you've prevented the default submit and then never turned it back over to the Validate plugin.) ASP or not, this is absolutely not the way to do it. The Validate plugin provides the submitHandler function for any purpose where you need to capture this event.

Your .settings.submitHandler works because it's the only way to define the submitHandler function when you have no access to write your own .validate() method (thanks to Unobtrusive Validation plugin). As per the documentation, the submitHandler is the "right place to submit a form via Ajax after it is validated".


so if I were not to use the unobtrusive, then I could use my original code?

The jQuery Validate plugin is initialized via the .validate() method, normally on page load. This method can only be called one time and all subsequent calls will be ignored. When you use ASP and the Unobtrusive Validation plugin, it constructs and calls the .validate() method for you, therefore you can no longer set any options or rules by calling .validate() yourself.