等待 form.submit() / POST 完成

Posted

技术标签:

【中文标题】等待 form.submit() / POST 完成【英文标题】:Wait for form.submit() / POST to complete 【发布时间】:2017-08-18 02:28:07 【问题描述】:

我在这里陷入了一个非常奇怪的境地。解释起来很复杂,但我会尽力而为。

问题的详细解释:

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

用户界面解释:

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

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

对于顶部的每个导航链接 <a> 元素,我有一个 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);
        );
    

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

$('.navLinks').on('click', LoadTabs);

我的下一个和上一个按钮基本上会触发点击事件,即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);

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

我的 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;

我的猜测是 form.submit 确实会被触发,但由于提交需要更长的时间才能完成,它会继续按钮 onclick 事件中的下一个代码块。

我首先认为这是一个服务器端问题,因为在 POST 中我通过几个循环保存了大量数据,并且任何处理繁重的代码块我都有那部分

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

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

如果有人能给我指明正确的方向,我将不胜感激。如果您需要更多信息,请告诉我,我很乐意提供!

【问题讨论】:

你为什么使用Ajax.BeginForm()是你使用$.ajax()。但问题是 ajax 是异步的。当您调用 ValidateForm() 并且它有效时,将对 POST 方法进行 ajax 调用。然后代码进入下一个$.ajax() 调用您的GET 方法。它们同时发生,无法保证哪个会先完成。 在非常简单的 ajax 表单提交和更新页面响应(从操作方法返回的部分视图)之前,我们没有这些验证逻辑。感谢您指出这一点。是的,我也这么认为...我只是想了解是否有办法停止/暂停代码运行直到 POST 完成... 不清楚“下一个”、“上一个”和“导航链接”按钮的用途。如果这是您必须按顺序完成每个步骤时的某种“向导”,那么您的表格 1-3 应该只有一个“下一步”提交按钮,而表格 4 应该有一个“完成”按钮(以及“栏”在顶部应该只是一个视觉指示器)。在任何情况下,您都应该处理表单.submit() 事件,检查isvalid()(如果是则取消),然后创建一个 $.post()`,该方法应该返回适​​当的局部视图以更新 DOM。 如果表格可以按任何顺序完成,那么用户当然应该能够跳转到他们想要的任何表格,即使他们已经开始完成之前的表格(也许你只是显示一个在允许他们转到另一个表格之前确认) 不幸的是,这就是应用程序 UI 结构的方式......我无法改变它。它实际上不仅仅是顶部的 4 个选项卡。顶部有 4 个主选项卡(大声笑),每个主选项卡有 4 个子选项卡(NavLinks - 圆圈/甜甜圈)。表单并不存在于每一页上。下一个/上一个是主视图的一部分,表格在我附加的那张照片中,那是一个局部视图容器,其中视图被动态加载......并且没有任何表格不能以任何顺序完成 - 至少在每个其中已填满,然后用户可以在应用程序中跳转。但是第一次 - 这是他们必须遵守的严格命令, 【参考方案1】:

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

    您调用ValidateForm() 函数(并假设其有效), 您的 $(form).submit(); 代码行开始制作 ajax POST 代码进行到最后的return true; 行,而 ajax 调用正在执行。 因为ValidateForm() 函数返回true,所以$.ajax GET 调用现在开始,但此时 ajax POST 在 ValidateForm() 函数可能没有完成执行导致 您的 GET 方法返回无效数据

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

$(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
    );
);

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

Deferred Object documentation和$.when()$.then()等的使用也值得一读。

【讨论】:

我最终使用了延迟对象。如果表单存在且有效,则返回$.post(),否则返回 deferred.resolve.promise()。我在$.then() 的回调函数中调用了$.get。我认为这解决了我的问题。感谢您抽出宝贵时间帮助我。

以上是关于等待 form.submit() / POST 完成的主要内容,如果未能解决你的问题,请参考以下文章

form submit时将__VIEWSTATE和__VIEWSTATEGENERATOR一起post到另外的页面,出现验证视图状态 MAC 失败。

form.submit() 将在表单内触发 double

form.submit 方法 并不会触发 form.onsubmit 事件

如何将数据附加到请求 form.submit()

js表单提交和submit提交的区别

form表单如何取得返回值