【问题标题】:How to get unobtrusive jquery remote validator to perform async..?如何让不显眼的 jquery 远程验证器执行异步..?
【发布时间】:2011-10-20 18:44:47
【问题描述】:

在 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 中,仅当相关文本框未能通过客户端上可能发生的验证时才会触发提交事件。例如,如果要求失败或正则表达式失败,则触发 submit()。对于远程验证操作方法,它不会被触发。但是,一旦客户端验证失败,后续的远程验证也会触发 IE8 提交事件。

对 Russ Cam 的回应(评论 #1)

下面是viewmodel中的相关代码:

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)
    {

很高兴您让我查看渲染后的 &lt;form&gt;。表单标签和输入元素如下所示:

<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="&amp;#39;Email Address&amp;#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")
}

我也在使用防伪令牌,如果这会有所不同的话。谢谢。

【问题讨论】:

  • 您能否同时显示视图模型代码和视图中的&lt;form&gt;
  • 发布了视图模型和渲染的 html,以及 cshtml 源代码。是 jquery validate 还是可以添加 novalidate 属性的不显眼的适配器?
  • 我以前从未见过 novalidate。它在 MVC 3 源代码中不存在。您还安装了哪些其他软件包?
  • 是的,我在所有表单中都看到了它。也许我应该开始一个新问题。 MVC 应用程序中的包:AutoMapper、CommonServiceLocator、ELMAH Core Library、Elmah.Contrib.Mvc、EF4.1、jQuery、jq UI、jq Validation、jq Visual Studio 2010 Intellisense、MicrosoftWebMvc、Modernizr、Mvc Html5 Templates、Mvc2Futures、MvcScaffolding、T4MVC 、T4Scaffolding、Unity、Windows Azure AppFabric 缓存、Windows Azure Web 角色。
  • 找到了,jquery.validate 1.9.0。刚升级。来自 jquery.validate.js,第 32 和 33 行://如果 HTML5,则添加 novalidate 标记。 this.attr('novalidate', 'novalidate');

标签: jquery asp.net-mvc-3 jquery-validate unobtrusive-validation remote-validation


【解决方案1】:

这有点 hacky,但我建议尝试以下方法。

首先,使用display="none" 隐藏提交按钮,并显示您自己的“提交”按钮,该按钮运行您上面的脚本。

其次,在您的页面中,添加一个标志 var [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
}

这将允许您等待挂起的远程验证完成,然后正常进行。我还没有测试过,所以你可能需要尝试一下才能让这个工作如你所愿。

【讨论】:

  • 哦,我不喜欢间隔。不要太介意settimeout,我最终使用了它。不过谢谢你,我可以稍后再试。
  • 当我尝试这样做时,我在 pendingRequets 上得到一个未定义?
【解决方案2】:

我有点迟到了,但我在尝试解决类似问题时偶然发现了这个问题。我也不想使用 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);
};

出于我的目的,我想做的只是将“加载”css 类添加到相邻的验证消息字段以显示加载 gif,但您可以轻松扩展它以启用/禁用按钮等。

【讨论】:

    【解决方案3】:

    昨晚我发现自己对此感到困惑,在尝试了各种方法后,我最终得到了辅导员的演变。由于辅导员没有直接开箱即用,我想我会分享它以防止其他人有同样的头痛。它不像我想要的那样“干净”的解决方案(我真的很讨厌使用间隔)。但这似乎就足够了。

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

    【讨论】:

      【解决方案4】:

      我最终解决了这个问题,但按钮禁用/等待图像显示仅在有有效提交的表单时才会发生。不过没关系,因为多个无效表单提交是幂等的,用户可以随意点击。 (此外,远程验证操作方法会根据其参数值进行缓存。)

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

      这也有点 hacky,但是当我不使用 setTimeout 时,提交操作永远不会触发无效的处理程序。

      【讨论】:

      • 现在我重新阅读了这篇文章,我意识到它会因为通过 ajax 加载的表单而中断。提交将禁用,但无效的处理程序将永远不会重新启用。将不得不尝试辅导员的黑客...
      【解决方案5】:

      我经历了所有的方法,一切都很好,但对我没有任何帮助。 然后我检查模型(类或 DTO)项目的 System.Web.Mvc 的版本,并且和 View 的项目存在版本差异。我将两者更新到相同的版本,它对我有用。

      我检查了 html 生成是否丢失 data-val-remote-additionalfields=".Email" 例如,我正在检查它们。

      【讨论】:

        猜你喜欢
        • 2013-01-20
        • 2014-05-29
        • 1970-01-01
        • 2023-03-14
        • 1970-01-01
        • 2013-10-17
        • 1970-01-01
        • 1970-01-01
        • 2020-12-27
        相关资源
        最近更新 更多