向远程验证属性MVC3添加延迟

时间:2011-11-17 10:41:11

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

我有一个senario,我必须在进行注册页面时检查数据库中是否存在用户名。为此我已经在我的模型中实现了远程属性的远程属性

[Remote("CheckUserNameAvaliable", "User", Httpmethod="Post")]
public string Username {get; set;}

我的方法看起来像这样

[HttpPost]
public JsonResult CheckUserNameAvaliable(string UserName)
{
    SessionUser currentUser = this.sessionHelper.GetCurrentUser();
    User user = this.userService.GetByUsername(UserName);
    if (user != null && user.Id != currentUser.Id)
    {
        return Json(false);
    }

    return Json(true);
}

它适用于我,但问题是,每当我们在用户名Textbox上创建一个密钥时,它将提交此远程验证,但根据我的要求,我必须在用户名输入值后才启动此远程验证文本框。为此,我们可以强制添加延迟到远程验证属性?

有谁知道如何在MVC3中为远程验证添加延迟?

4 个答案:

答案 0 :(得分:3)

MVC3在浏览器中使用jquery.validate插件。使用jquery.validate,字段验证直到第一次更改和字段模糊才开始,或者在未提交字段时提交。

对字段启动字段验证后,验证程序的onkeyup设置将控制是否对每个keyup事件执行验证。如果你在每个键按下的字段上执行远程验证,它可能会发送太多的ajax消息,同时强调客户端和服务器。

正如其他响应者所提到的,您可以通过设置validator.settings.onkeyup = false来抑制keyup验证,但这会抑制所有表单字段上的onkeyup验证,而不仅仅是那些具有远程验证规则的字段。我建议您在具有远程验证的字段具有焦点时抑制键入,然后在模糊字段时将其重新打开。

抑制onkeyup很容易。问题是将设置从false更改为true不会重新打开该功能。要重新打开它,您需要将其设置为$ .validator对象的默认值中定义的函数。

如果您正在使用MVC不显眼的验证,那么这是您的网页上包含的JavaScript代码。它将涵盖您网页上的所有表单。并确保使用jquery.validate版本1.9.0或更高版本'因为早期版本无法与IE 7或8一起正常工作(是的,我也必须支持这些用户):

    $("form input[data-val-remote-url]").on({
        focus: function () {
            $(this).closest('form').validate().settings.onkeyup = false;
        },
        blur: function () {
            $(this).closest('form').validate().settings.onkeyup =
                $.validator.defaults.onkeyup;
        }
    });

答案 1 :(得分:2)

在使用MVC3和远程验证之前,我遇到过类似的问题。猜猜你希望事件在模糊时触发但不确定你如何告诉远程验证......

希望这会有所帮助

ASP.NET Remote Validation only on blur?

答案 2 :(得分:0)

如果你不想在密钥上验证但是在模糊上,则this就是你想要的

答案 3 :(得分:0)

没有一种方法是合适的答案,因为它消除了在错误已显示时重新验证 keyup 的能力。我仍然想要一个去抖动,而不是在每个键上点击 API 的当前实现。

我的解决方案是覆盖远程方法。

// Will use a simple variable to hold our current remote API request
// may want to do something smarter later
var holderForCurrentRemoteCall = null;

// keep the original as we're going to make use of it
jQuery.validator.methods._remoteRule = jQuery.validator.methods.remote;

jQuery.validator.methods.remote = function (value, element, param, method) {
    // the orig remote method sets a pending class when the call is in progress
    // we'll quickly exit and continue the pending.
    if ($(element).hasClass('pending')) { return 'pending'; }

    // we're going to need the previous value to stop any
    // mid-stream request
    method = typeof method === "string" && method || "remote";
    var previous = this.previousValue(element, method);

    if (holderForCurrentRemoteCall != null) {
        // stop any current request
        this.stopRequest(element, previous.valid);
        // and clear out any timeout that hasn't executed yet
        clearTimeout(holderForCurrentRemoteCall);
        holderForCurrentRemoteCall  = null;
    }

    // Within the orig remote call, it has some mnemonic so it won't
    // make the same request twice
    // as we can't capture it here, bubbling the request to orig would
    // not give a desirable outcome for our stub. 
    // so I've taken the mnemonic part of the code and replicate here
    if (this.optional(element)) {
        return "dependency-mismatch";
    }

    if (!this.settings.messages[element.name]) {
        this.settings.messages[element.name] = {};
    }
    previous.originalMessage = previous.originalMessage || this.settings.messages[element.name][method];
    this.settings.messages[element.name][method] = previous.message;

    param = typeof param === "string" && { url: param } || param;
    var optionDataString = $.param($.extend({ data: value }, param.data));
    if (previous.old === optionDataString) {
        return previous.valid;
    }
    // End copy-pasta code

    holderForCurrentRemoteCall  = setTimeout(() => {
        jQuery.validator.methods._remoteRule.call(this, value, element, param, method);
        // remove the holder as we have nothing to cancel
        holderForCurrentRemoteCall = null;
    }, 300);

    return "pending";
}