在一个MVC3应用程序中,使用jquery不显眼的验证,以及一个带有[Remote]验证器的视图/模型:我试图在远程验证期间禁用提交按钮并显示等待图标,当一个有效的表单提交给服务器时。我以为我已经搞定了,直到我在IE8中尝试了一下。
问题是,当表单无效时,GC和FF没有触发表单的提交事件,所以我在此事件期间禁用了提交按钮。然而,IE8在表单无效时触发此事件,导致用户永远无法再次单击它。(IE8不提交表单,但是事件被触发)
我试着给提交按钮的点击事件附加一个函数。在这里,我禁用了提交按钮,显示了等待图标,并有如下内容:
$('[data-app-form-submit-button="true"]').live('click', function (e) {
var form = $(this).parents('form');
var icon = form.find('[data-app-form-submitting-icon="true"]');
icon.show();
$(this).attr('disabled', 'disabled');
$.ajaxSetup({ async: false });
var isValid = form.valid();
$.ajaxSetup({ async: true });
alert(isValid);
});
问题是,ajax设置调用并没有真正关闭异步。如果我把它移出点击功能,它会,但它会禁用所有的异步。相反,页面会立即发出"true"警报,并通过在远程验证操作方法上设置一个断点进行测试。
任何想法?
额外注意:
我忘了说,在IE8中,只有当有问题的文本框没有通过客户端验证时才会触发提交事件。例如,如果它没有通过required或regex,则会触发submit()。对于远程验证操作方法,它不会被触发。但是,一旦客户端验证失败,后续的远程验证也会触发IE8提交事件。
对Russ Cam的回应(评论#1)
以下是视图模型中的相关代码:public class SignUpForm : IValidatableObject
{
[DataType(DataType.EmailAddress)]
[Display(Name = "Email Address")]
[Required(ErrorMessage = "Email Address is required.")]
[RegularExpression(@"^(email regex here)$",
ErrorMessage = "This is not a valid email address.")]
[Remote("Validate", "ControllerName", "AreaName", HttpMethod = "POST")]
public string EmailAddress { get; set; }
public IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
我很高兴你让我看渲染的<form>
。表单标签和输入元素看起来像这样:
<form action="/post-action-method" method="post" novalidate="novalidate">
...
<input class="text-box single-line" data-app-focus="true" data-val="true"
data-val-regex="This is not a valid email address."
data-val-regex-pattern="^(email regex here)$"
data-val-remote="&#39;Email Address&#39; is invalid."
data-val-remote-additionalfields="*.EmailAddress"
data-val-remote-type="POST"
data-val-remote-url="/validate-action-method"
data-val-required="Email Address is required."
id="EmailAddress" name="EmailAddress" type="text" value="">
...
<input type="submit" value="Submit this form"
data-app-form-submit-button="true" />
直到现在我才看到novalidate="novalidate"属性。下面是cshtml文件中的内容:
@using (Html.BeginForm())
{
@Html.EditorForModel()
@Html.AntiForgeryToken("assault")
}
我也使用防伪令牌,如果这有区别的话。谢谢。
这有点俗套,但我建议您尝试以下方法:
首先,用display="none"
隐藏提交按钮,并显示你自己的"提交"按钮,它运行上面的脚本。
var remotePending = false;
]和一个变量用于setInterval
调用[var intervalPending;
],并在您的脚本中,将标志设置为true,然后使用intervalPending = setInterval('remoteCheck()', 200);
调用以下函数
function remoteCheck() {
if ($.validator.pendingRequest == 0) {
// requests are done
// clear interval
clearInterval(intervalPending);
// re-enable our "submit" button
// "click" the hidden button
$("#hiddenSubmit").click();
}
// we will try again after the interval passes
}
这将允许您等待挂起的远程验证完成,然后正常进行。我还没有测试过,所以你可能要玩周围的工作,因为你想要的
我有点晚了,但是我在试图解决类似问题时偶然发现了这个问题。我也不想使用Interval,所以我想出了一个不同的解决方案,并认为值得在这里详细说明。
最后,我决定重写jQuery验证器startRequest和stopRequest方法,以便添加我自己的逻辑。在执行我自己的逻辑之后,我简单地调用旧的验证器方法。
// Extend jQuery validator to show loading gif when making remote requests
var oldStartRequest = $.validator.prototype.startRequest;
$.validator.prototype.startRequest = function (element) {
var container = $('form').find("[data-valmsg-for='" + element.name + "']");
container.addClass('loading');
oldStartRequest.apply(this, arguments);
};
var oldStopRequest = $.validator.prototype.stopRequest;
$.validator.prototype.stopRequest = function (element) {
var container = $('form').find("[data-valmsg-for='" + element.name + "']");
container.removeClass('loading');
oldStopRequest.apply(this, arguments);
};
我想做的只是简单地添加一个'loading' css类到相邻的验证消息字段,以显示一个正在加载的gif,但你可以很容易地扩展它来启用/禁用按钮,等等
昨晚我发现自己对这个问题感到困惑,在尝试了各种方法之后,我最终找到了一个进化的辅导员。由于咨询师们并不是直接开箱工作,我想我应该分享一下,以防止其他人也有同样的头痛。这并不是我想要的"干净"的解决方案(我真的很讨厌使用间隔)。但这似乎已经足够了。
var iIntervalId = null;
//
// DECLARE FUNCTION EXPRESSIONS
//
//==============================================================================
// function that triggers update when remote validation completes successfully
//==============================================================================
var fnPendingValidationComplete = function () {
var validator = $("#frmProductType").data("validator");
if (validator.pendingRequest === 0) {
clearInterval(iIntervalId);
//Force validation to present to user (this will not retrigger remote validation)
if ($("#frmProductType").valid()) {
alert("valid - you can submit now if you like");
}
//else { alert("invalid"); }
}
//else { alert("NOT YET"); }
},
//==============================================================================
// Trigger validation
//==============================================================================
fnTriggerValidation = function (evt) {
//Remove any cached values to ensure that remote validation is retriggered
$("#txtProductType").removeData("previousValue");
//Trigger validation
$("#frmProductType").valid();
//Setup interval which will evaluate validation (this approach because of remote validation)
iIntervalId = setInterval(fnPendingValidationComplete, 50);
};
fnTriggerValidation();
我最终解决了这个问题,但是按钮禁用/等待图像显示只发生在有一个有效的提交表单时。不过没关系,因为多个无效表单提交是幂等的,用户可以想点击多少就点击多少。(另外,远程验证操作方法是根据其参数值缓存的。)
$(function () {
$('form').bind('invalid-form.validate', function () {
$('form').each(function () {
$(this).find(
'[data-app-form-submitting-icon="true"]').hide();
var button = $(this).find(
'input[type="submit"][data-app-form-submit-button="true"]');
setTimeout(function () {
button.removeAttr('disabled');
}, 1);
});
});
$('form').live('submit', function (e) {
$(this).find('[data-app-form-submitting-icon="true"]').show();
var button = $(this).find(
'input[type="submit"][data-app-form-submit-button="true"]');
setTimeout(function () {
button.attr('disabled', 'disabled');
}, 0);
});
});
这也有点笨拙,但是当我不使用setTimeout时,提交动作永远不会触发无效的处理程序。
我尝试了所有的方法,都很好,但没有一种对我有效。然后我检查了模型(类或DTO)项目的System.Web.Mvc的版本和View的项目有版本差异。我将两者更新到相同的版本,它对我有效。
我检查html生成丢失data-val-remote-additionalfields =".Email"例:我正在检查它们。