jquery - focusout 上的验证消息移动按钮,它可以防止 onclick 事件
问题描述
我有一个 JQuery 验证,可以验证焦点输出的字段,并在出现错误时在该字段下显示一个标签。
当我第一次聚焦该字段并输入无效值并单击该字段下的按钮时,出现验证消息,由于focusout事件而显示错误消息并且按钮的单击事件没有触发。
当事件的relatedTarget 是我的按钮时,我尝试在focusout 事件上添加preventdefault 并且它有效,因为验证没有触发。但我认为这不是纠正这个问题的好方法,因为我必须阻止对我拥有的应用程序中的所有按钮或控件进行验证,所以验证似乎没用。
我可以改为在 keyup 上触发验证,因此当 focusout 触发时验证消息已经存在,但是当有一个验证验证字段是否为 10 个字符长时,例如,它会在用户事件输入之前显示错误消息完整的价值。
我可以将验证消息放在其他地方,这样它就不会移动我的按钮,但是该字段下的验证消息是我工作的规范。
在下面的示例中,我有以下情况,其中字段验证为 MaxLength(5) :
- 当我第一次单击按钮时,我有警报。
- 当我在字段中输入“abc”并单击按钮时,我会收到警报。
- 当我在字段中输入“123456”并在字段外单击时,我会在字段下显示错误消息,然后如果我单击按钮,我会收到警报。
- 当我在字段中输入“123456”并单击按钮时,我有消息在字段下但没有警报。
我的模型:
using System.ComponentModel.DataAnnotations;
namespace TestClickValdiation.Models
{
public class TestValidation
{
[MaxLength(5)]
public string Test { get; set; }
}
}
查看开始:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
布局 :
<!DOCTYPE html>
<html>
<head>
</head>
<body>
@RenderBody()
</body>
</html>
我的观点 :
@model TestClickValdiation.Models.TestValidation
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
@using (Html.BeginForm("Go", "Home", FormMethod.Post))
{
<div>
<div>
@Html.EditorFor(x => x.Test, new { htmlAttributes = new { @class = "form-control" } })
</div>
<div>
@Html.ValidationMessageFor(x => x.Test)
</div>
</div>
<button type="submit" onclick="window.alert('hello');">Submit</button>
}
全球.asax:
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace TestClickValdiation
{
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
我的控制器:
using System.Web.Mvc;
using TestClickValdiation.Models;
namespace TestClickValdiation.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
TestValidation test = new TestValidation();
return View(test);
}
public ActionResult Go(TestValidation test)
{
return View("Index", test);
}
}
}
我想要的是在最后一种情况下显示验证消息并显示警报。所以以下步骤:
- 在字段中输入“123456”
- 点击按钮
- 字段显示下的消息。
- 警报显示。
现在只显示字段下的消息。
我从我的 jQuery 导入中删除了 .min 以在其中调试并测试使用 focusout 和 maxlength 属性的位置。
focusout 事件在 jQuery.validate.js 中:
onfocusout: function( element ) {
if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
this.element( element );
}
},
之后调用元素并在其中调用检查函数,然后为每个规则调用验证方法(在这种情况下为 maxlength)
check: function( element ) {
element = this.validationTargetFor( this.clean( element ) );
var rules = $( element ).rules(),
rulesCount = $.map( rules, function( n, i ) {
return i;
} ).length,
dependencyMismatch = false,
val = this.elementValue( element ),
result, method, rule, normalizer;
// Prioritize the local normalizer defined for this element over the global one
// if the former exists, otherwise user the global one in case it exists.
if ( typeof rules.normalizer === "function" ) {
normalizer = rules.normalizer;
} else if ( typeof this.settings.normalizer === "function" ) {
normalizer = this.settings.normalizer;
}
// If normalizer is defined, then call it to retreive the changed value instead
// of using the real one.
// Note that `this` in the normalizer is `element`.
if ( normalizer ) {
val = normalizer.call( element, val );
if ( typeof val !== "string" ) {
throw new TypeError( "The normalizer should return a string value." );
}
// Delete the normalizer from rules to avoid treating it as a pre-defined method.
delete rules.normalizer;
}
for ( method in rules ) {
rule = { method: method, parameters: rules[ method ] };
try {
result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
...
然后是maxlength验证方法
// https://jqueryvalidation.org/maxlength-method/
maxlength: function( value, element, param ) {
var length = $.isArray( value ) ? value.length : this.getLength( value, element );
return this.optional( element ) || length <= param;
},