我在这里遇到了一个非常奇怪的情况。解释起来很复杂,但我会尽我所能。
我有一个顶部有4个导航<a>
按钮的用户界面 - 中间位置总是一个表单 - 而在底部我有以前的&amp;下一步按钮。
使用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);
我的下一个&amp;以前的按钮基本上会触发点击事件,即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处于活动状态并且我点击了NEXT按钮 - 而不是首先通过form.submit()发布表单 - 导航4被触发 - 因此导航4的GET运行之前表格导航3.
我的ValidateForm方法基本上只是检查表单是否存在且有效然后是Submit,否则返回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
事件中的下一个代码块。
我首先认为这是C#问题,因为在POST中我用一些循环保存了大量数据,并且任何代码块处理繁重我都有
var saveTask = Task.Factory.StartNew(() => ControllerHelper.SomeMethod(db, model));
Task.WaitAll(saveTask);
WaitAll将等待并暂停执行,直到SomeMethod完成执行。我不知道如何在javascript中锁定进程并等待它完成执行。因为我认为如果我可以以某种方式锁定ValidateForm中的form.submit()直到它完成处理..通过回调方法也许...
如果有人能指引我正确的方向,我非常感谢你的帮助。如果您需要更多信息,请告诉我,我很乐意提供!
答案 0 :(得分:2)
我发布这是对Alan的说明,因为它是多行代码,我无法在评论中使其可读。为了避免在有时运行异步操作时出现反模式,有时候不能使用,我可以使用:
function ValidateForm(){
// do your logic
if (pass) {
return $.post("urlToPost");
else {
return $.Deferred().reject(xxx).promise();
}
}
这样,你总是会回复一个承诺。在一个案例中,承诺来自$.ajax()
。在另一种情况下,由于操作已经失败,您只是返回被拒绝的承诺。
答案 1 :(得分:1)
作为jfriend00评论原始答案回归的方式是承诺是反模式,更好的方法是:
function ValidateForm(){
// do your logic
if (pass) {
return $.post("urlToPost");
else {
return $.Deferred().reject(xxx).promise();
}
}
关于此的更多信息,结帐https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns
我会尝试描绘你的问题:
你想要的是首先运行ValidateForm
,当它过去时(这样当表格发布完成时),然后执行MoveNext
问题是,MoveNext
在ValidateForm
完成之前被调用。
如果我是正确的,那么原因是因为Javascript本质上是异步编程,所以当事情发生时使用回调来触发。
所以在你的情况下,你需要使用诺言来实现它。
essentialy你需要做的是:
ValiateForm
返回承诺MoveNext
完成后才执行ValidateForm
所以代码就像:
function ValiateForm(){
var dfd = jQuery.Deferred();
// do your logic
if(pass){
$.post("urlToPost"
} else {
// also failed
dfd.reject();
}
// return the promise
return dfd.promise();
}
然后您的移动下一个按钮就像
$('button').on('click', function () {
if (this.id === "btnMoveToNextTab") {
$.when(window.ValidateForm(true)).then(function(){
// after success post form
$.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;
});
});
有关承诺结帐的更多信息
https://api.jquery.com/deferred.promise/
完成后运行