等待form.submit()/ POST完成

Joh*_*hny 3 javascript c# asp.net-mvc jquery asp.net-mvc-5

我陷入了一个非常奇怪的情况。解释起来很复杂,但我会尽力而为。

问题的详细说明:

在导航的每个顶部单击(绿色甜甜圈/圆圈)或下一步按钮,如果存在并且有效,则必须提交该表单。如果无效,form.valid()会触发验证错误,返回false将停止任何进一步的传播。在我发现一个奇怪的行为(不是很持久)之前,此设置可以正常工作。具体来说,我第3个标签上的表格数据量很大。当我点击下一步按钮时,它实际上应该经过相同的过程:检查现有表格(如果有效),然后提交。Submit会调用POST操作方法,发布完成后将获取下一个选项卡的视图。它像这样运行5/10次,但有时GET在POST之前执行,这会导致下一页加载不完整的数据。当我放置断点进行调试时,我看到下一个选项卡的GET在当前选项卡的POST之前执行。

用户界面说明:

我有一个UI,<a>顶部有4个导航按钮-中心始终有一个表单-底部有上一个和下一个按钮。

在此处输入图片说明

使用MVC在MVC中构造表单 Ajax.BeginForm

对于<a>顶部的每个Nav链接元素,我都有一个JavaScript函数

var LoadTabs = function (e, arg) {  
    // This is to validate a form if one of the top links is clicked and form has incomplete fields...
    if (arg !== "prev" && arg !== "next") {
        if (!window.ValidateForm(false)) return false;
    }

    var url = $(this).attr('data'); // this contains link to a GET action method
    if (typeof url != "undefined") {
        $.ajax(url, { context: { param: arg } }).done(function (data) {                
            $('#partialViewContainer').html(data);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的函数绑定到页面加载时的每个顶部链接。

$('.navLinks').on('click', LoadTabs);
Run Code Online (Sandbox Code Playgroud)

我的下一个和上一个按钮基本上触发点击事件,即LoadTabs功能。

$('button').on('click', function () { 
        if (this.id === "btnMoveToNextTab") {
            if (!window.ValidateForm(true)) return false;                

            $.ajax({
                url: url,
                context: { param: 'next' },
                method: "GET",
                data: data,
                success: function(response) {
                    if (typeof response == 'object') {
                        if (response.moveAhead) {
                            MoveNext();
                        }
                    } else {
                        $('#mainView').html(response);
                    }
                    ScrollUp(0);
                }
            });
        } 

        if (this.id === "btnMoveToPreviousTab") {
            MoveBack();
        }
        return false;
    });


MoveNext() Implementation is as below:

function MoveNext() {        
    var listItem = $('#progressbarInd > .active').next('li');        

    listItem.find('.navLink').trigger('click', ['next']);
    ScrollUp(0);
}
Run Code Online (Sandbox Code Playgroud)

问题是由于某些原因,当导航链接3处于活动状态并且我按下了NEXT按钮时-而不是首先通过form.submit()发布表单-触发了导航4-因此导航4的GET在导航POST之前运行3。

我的ValidateForm方法基本上只是检查表单是否存在并且有效,然后再提交,否则返回false。其如下:

function ValidateForm(submit) {

    var form = $('form');

    // if form doesn't exist on the page - return true and continue
    if (typeof form[0] === "undefined") return true;

    // now check for any validation errors
    if (submit) {
        if (!$(form).valid()) {                
            return false;
        } else {
            $(form).submit();
        }
    } 
    else {
        return true;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

我的猜测是form.submit确实按应有的方式被触发,但是由于submit需要花费更长的时间才能完成,因此继续按钮onclick事件中的下一个代码块。

我首先以为这是服务器端的问题,因为在POST中,我通过一些循环保存了大量数据,而任何处理过程繁重的代码块都包含在其中

var saveTask = Task.Factory.StartNew(() => ControllerHelper.SomeMethod(db, model)); Task.WaitAll(saveTask);

WaitAll将等待并暂停执行,直到SomeMethod完成执行。我不确定如何在JavaScript中锁定进程并等待其完成执行。因为我认为如果我可以通过某种回调方法将Form.submit()锁定到ValidateForm中,直到完成处理.....

如果有人可以引导我走正确的方向,请给我很大的帮助。如果您需要更多信息,请告诉我,我们很乐意提供!

小智 5

Ajax是异步的,正在使用的表单提交Ajax.BeginForm()正在使用ajax。发生的是,当您单击“下一步”按钮时,将触发$('button').on('click', function () {代码:

  1. 您调用该ValidateForm()函数(并假设其有效),您$(form).submit();的代码行开始进行ajax POST
  2. return true;执行ajax调用时,代码将前进到最后一行。
  3. 因为该ValidateForm()函数返回true,所以$.ajax 现在开始GET调用,但是此时ValidateForm()函数中的ajax POST 可能尚未完成执行,从而导致GET方法返回无效数据

您需要更改代码,以便在POST方法调用完成后进行GET调用。并且由于您在$.ajax()整个代码中都使用了这些方法,并且$.ajax()为您提供了更大的灵活性,因此似乎没有必要使用Ajax.BeginForm()(以及包括jquery.unbtrusive-ajax.js脚本在内的额外开销)。您还应该处理表单.submit()功能(如果您不希望“下一步”按钮成为表单中的提交按钮,则可以.submit()在按钮.click()处理程序中触发事件)

$(document).on('submit', 'form', function(e) {
    e.preventDefault(); // cancel default submit
    var form = $(this);
    if (!form.valid()) {
        return; // will display the validation errors
    }
    .... // get the relevant urls to the GET and POST methods etc
    $.post(postUrl, form.serialize(), function(data) {
        .... // not clear if your [HttpPost] method returns anything
    }).done(function() {
        $.get(getUrl, someData, function(response) {
            .... // Update the DOM with the next form?
            .... // Re-parse the validator for client side validation
        }
    }).fail(function() {
        .... // code that you might run if the code in the [HttpPost] method fails
    });
});
Run Code Online (Sandbox Code Playgroud)

您还应该考虑在该[HttpPost]方法中返回适当的“下一个”视图,这样您就无需再次调用服务器来获取它。

还值得阅读Deferred Object文档和的使用$.when()$.then()等等。