等待 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 失败。