等待 form.submit()/POST 完成 [英] Wait for form.submit() / POST to complete

查看:30
本文介绍了等待 form.submit()/POST 完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个非常奇怪的情况.解释起来很复杂,但我会尽力的.

问题的详细说明:

<块引用>

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

用户界面解释:

我有一个 UI,顶部有 4 个导航 <a> 按钮 - 在中心总是有一个表单 - 在底部我有 Previous &下一个按钮.

使用 Ajax.BeginForm

在 MVC 中构造表单

对于顶部的每个导航链接 元素,我有一个 JavaScript 函数

var LoadTabs = function (e, arg) {//这是为了在单击顶部链接之一并且表单具有不完整的字段时验证表单...if (arg !== "prev" && arg !== "next") {如果 (!window.ValidateForm(false)) 返回 false;}var url = $(this).attr('data');//这包含指向 GET 操作方法的链接如果(网址类型!=未定义"){$.ajax(url, { context: { param: arg } }).done(function (data) {$('#partialViewContainer').html(data);});}}

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

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

我的下一个 &以前的按钮基本上触发点击事件,即 LoadTabs 功能.

$('button').on('click', function () {if (this.id === "btnMoveToNextTab") {如果 (!window.ValidateForm(true)) 返回 false;$.ajax({网址:网址,上下文:{参数:'下一个'},方法:获取",数据:数据,成功:功能(响应){if (typeof response == 'object') {如果(response.moveAhead){移动下一步();}} 别的 {$('#mainView').html(响应);}向上滚动(0);}});}if (this.id === "btnMoveToPreviousTab") {后退();}返回假;});MoveNext() 实现如下:函数移动下一步(){var listItem = $('#progressbarInd > .active').next('li');listItem.find('.navLink').trigger('click', ['next']);向上滚动(0);}

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

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

function ValidateForm(submit) {var form = $('form');//如果页面上不存在表单 - 返回 true 并继续if (typeof form[0] === "undefined") 返回真;//现在检查任何验证错误如果(提交){如果 (!$(form).valid()) {返回假;} 别的 {$(form).submit();}}别的 {返回真;}返回真;}

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

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

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

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

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

Ajax 是异步的,您使用 Ajax.BeginForm() 提交的表单正在使用 ajax.发生的事情是,当您单击下一步"按钮时,它会触发 $('button').on('click', function () { code:

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

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

$(document).on('submit', 'form', function(e) {e.preventDefault();//取消默认提交var form = $(this);如果(!form.valid()){返回;//将显示验证错误}....//获取 GET 和 POST 方法等的相关 url$.post(postUrl, form.serialize(), function(data) {....//不清楚您的 [HttpPost] 方法是否返回任何内容}).完成(功能(){$.get(getUrl, someData, function(response) {....//用下一个表单更新 DOM?....//重新解析验证器以进行客户端验证}}).失败(函数(){....//如果 [HttpPost] 方法中的代码失败,您可能会运行的代码});});

您还应该考虑在 [HttpPost] 方法中返回适当的next"视图,这样您就不需要再次调用服务器来获取它.>

还值得阅读延迟对象文档$.when()、$.then()

I'm stuck in a really bizarre situation here. It's complicated to explain but I'll try my best.

Detailed explanation of the issue:

On every top Nav click (Green donuts/circles), or next button, I must submit the form, if it exists and is valid. If not valid, form.valid() triggers validation errors and return false would stop any further propagation. This setup was working flawlessly until I noticed a strange behavior which isn't very persistence. Form on my 3rd tab, specifically, is quite data heavy. When I hit next button it should practically go thru the same process: check for an existing form, if valid, then submit. Submit calls the POST action method and when post completes it GETs the view for next tab. It works like this 5/10 times but at other times GET executes before the POST, which causes next page to load with incomplete data. When I put breakpoints to debug, I see GET for the next tab executing before POST of the current tab.

UI Explained:

I have a UI with 4 navigation <a> buttons on top - in the center there's a always a form - and at the bottom I have Previous & Next buttons.

Forms are constructed in MVC using Ajax.BeginForm

For each Nav link <a> element on top, I have a JavaScript function

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);
        });
    }
}

This function above binds to each top link on page load.

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

My Next & Previous buttons basically trigger the click event i.e. LoadTabs function.

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

The problem is, for some reasons, when Nav Link 3 is active and I hit NEXT button - Instead of posting the form first via form.submit() - the nav 4 gets triggered - hence GET for nav 4 runs before form POST of nav 3.

My ValidateForm method is basically just checking if the form exists and is valid then Submit, else returns false. Its as below:

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;
}

My speculation is that form.submit does get triggered as it should be but since submit takes a little longer to finish it continues with the next code block in the button onclick event.

I first thought that this is a server side issue as in the POST I'm saving a big chunk of data with a few loops, and any code block that's process heavy I have that part in

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

WaitAll will wait and pause the execution until SomeMethod finishes executing. I'm not sure how can I lock a process in JavaScript and wait for it to finish execution. Because I think If i can somehow lock the form.submit() in ValidateForm until its finished processing .. via a callback method perhaps...

Please if anyone can put me in right direction, I'd greatly appreciate the help. If you need more information please let me know I'd be happy to provide!

解决方案

Ajax is async, and your forms submit which is using Ajax.BeginForm() is using ajax. What is happening is that when you click your 'Next' button, which triggers the $('button').on('click', function () { code:

  1. You call the ValidateForm() function (and assuming its valid), your $(form).submit(); line of code starts making a ajax POST
  2. The code progresses to the final return true; line while the ajax call is executing.
  3. Because the ValidateForm() function returned true, the $.ajax GET call now starts, but at that point the ajax POST in the ValidateForm() function may not have finished executing causing your GET method to return invalid data

You need to change your code so that the GET call is made once the POST method call has completed. And since your using the $.ajax() methods throughout your code, and $.ajax() gives you more flexibility, it seems unnecessary to use Ajax.BeginForm() (and the extra overhead of including the jquery.unbtrusive-ajax.js script). You should also be handling the forms .submit() function (if you do not want the 'Next' button to be a submit button in the form, you could just trigger the .submit() event in the buttons .click() handler)

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

You should also consider returning the appropriate 'next' view in the [HttpPost] method so that you don't then needs to make a second call back to the server to get it.

It is also worth reading the Deferred Object documentation and the use of $.when(), $.then() etc.

这篇关于等待 form.submit()/POST 完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆