【问题标题】:Custom validation works server side but not client side asp mvc 5自定义验证适用于服务器端,但不适用于客户端 asp mvc 5
【发布时间】:2015-02-24 00:24:15
【问题描述】:

我有一个自定义验证类来验证日期。它适用于服务器端,但不适用于客户端。我无法触发 jquery 方法进行检查。我想我的适配器或验证器可能连接不正确。 附:我可以让非自定义客户端验证工作(例如 [必需]),而不是我的自定义验证

查看模型

public class HomePageViewModel
{
    [Required]
    public string SearchQuery { get; set; }

    [DisplayName("Date")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [ClassDate(ErrorMessage = "Class date must be today or later.")]
    public DateTime ClassDate { get; set; }
}

验证类。

public class ClassDateAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value == null) // ok, just use todays date day
        {
            return true;
        }

        DateTime toValidate = (DateTime) value;

        if (toValidate.Day < DateTime.Now.Day) // if they are looking for classes in the past
        {
            return false;
        }
        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,
        ControllerContext context)
    {
        var classDateRule = new ModelClientValidationRule();
        classDateRule.ErrorMessage = "test error message";
        classDateRule.ValidationType = "classdate"; 

        yield return classDateRule;
    }
}

Javascript 代码。

$(function () {
$(".datefield").datepicker();
var now = new Date();

var day = ("0" + now.getDate()).slice(-2);
var month = ("0" + (now.getMonth() + 1)).slice(-2);

var today = (month) + "/" + (day) + "/" + now.getFullYear();

$('.datefield').val(today);


$.validator.unobtrusive.adapters.addSingleVal("classdate");

$.validator.addMethod("classdate", function(value) {
    if (value) {
        //do something to test date here
        //if date is today or later
        return true;
    }
    return false;
});
});

这是我认为的元素。

 @Html.TextBoxFor(model => model.ClassDate, new { @class = "datefield form-control", @id = "ClassDate", @type = "date", name = "ClassDate" })
 @Html.ValidationMessageFor(model => model.ClassDate, "", new { @class = "text-danger" })

【问题讨论】:

  • 既然您使用了数据选择器(假设这是 jquery ui),那么为什么不直接设置minDate: 0,? (以及为什么你有@id = "ClassDate", @type = "date", name = "ClassDate" - 所有这些都是毫无意义的,因为无论如何这都是助手渲染的)
  • 我想我会用当前时间将 minDate 设置为今天。我不希望任何人选择过去的日期/时间。但是为了让这个连接起来,你能看到任何问题吗?我知道我需要在项目的其他领域进行自定义客户端验证,因此了解这里发生的情况会有所帮助。

标签: javascript jquery asp.net-mvc validation


【解决方案1】:

您没有获得客户端验证的主要问题是您使用了$.validator.unobtrusive.adapters.addSingleVal("classdate");addSingleVal() 用于验证模型中的另一个属性。必须是$.validator.unobtrusive.adapters.addBool("classdate");

由于您使用的是 jQueryUI 日期选择器,因此您可以使用

阻止选择小于今天日期的日期
$(.datefield).datepicker({
  minDate: 0
});

这里的很多代码没有意义(见下面的附注),应该是这样的

属性定义

[DisplayName("Date")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[NotLessThanToday]
public DateTime ClassDate { get; set; }

验证属性

public class NotLessThanTodayAttribute : ValidationAttribute, IClientValidatable
{
  private const string _DefaultErrorMessage = "The property {0} cannot be less than todays date";

  public NotLessThanTodayAttribute() : base(_DefaultErrorMessage)
  {
  }

  public override string FormatErrorMessage(string name)
  {
    return string.Format(ErrorMessageString, name);
  }

  protected override ValidationResult IsValid(object value, ValidationContext validationContext)
  {
    if (value == null)
    {
      return ValidationResult.Success; // ??
    }
    DateTime date = DateTime.Today;
    if (DateTime.TryParse((string)value, out date))
    {
      if (date < DateTime.Today)
      {
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
      }
    }
    else
    {
      // not a valid date
    }
    return base.IsValid(value, validationContext);
  }

  public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
  {
    var clientValidationRule = new ModelClientValidationRule()
    {
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
      ValidationType = "notlessthantoday"
    };
    return new[] { clientValidationRule };
  }
}

脚本

$.validator.addMethod("notlessthantoday", function (value, element, params) {
  if (!this.optional(element)) {
    var date = new Date(value);
    var today = new Date();
    return date > today;
  }
  return true; // ??
});

$.validator.unobtrusive.adapters.addBool("notlessthantoday");

附注

  1. ApplyFormatInEditMode = true[DataType(DataType.Date)]@Html.EditorFor() 渲染 浏览器 HTML5 日期选择器。这里没有必要,如果你这样做了 使用它,格式字符串需要为"{0:yyyy-MM-dd}"(ISO 格式)
  2. 您当前的验证属性仅检查日期是否为天 比今天少。 if (toValidate.Day &lt; DateTime.Now.Day) 表示1/1/2016 有效(1 小于24)。
  3. 脚本var now = new Date(); ..... $('.datefield').val(today); 没有意义并覆盖模型中的值(用户输入 日期,您发布并返回视图,您的代码将重置日期 回到今天的价值!)。如果要显示今天的日期,则 在将模型传递给视图之前设置模型中的值 (model.ClassDate = Datetime.Today;)
  4. 您在帮助程序中设置(或尝试)以下属性: @id="ClassDate", @type="date", name="ClassDate"。 html 助手 无论如何将id 属性设置为id="ClassDate"。这 type="date" 不是必需的(用于渲染浏览器 HTML5 datepicker) 并按照您的操作设置 name 属性 什么都没有(幸运的是它不起作用,因为你试图给 它是“ClassDate”以外的名称,绑定会失败)

【讨论】:

  • 我相信你的代码是正确的。我直接复制并粘贴到我的项目中。但是当我提交表单并在 javascript 中设置断点时,它永远不会被调用并且断点永远不会被命中。 NotLessThanTodayAttribute 中的 IsValid 方法被调用,就好像禁用了客户端验证一样。我认为我的所有库都已正确安装并以正确的顺序调用,并且我将 web.config 中的属性设置为 true 以进行客户端验证。但我可能是错的!
  • 首先检查生成的html是否包含data-val-notlessthantoday="The field ClassDate cannot be less than todays date"。还要确保您没有将脚本包装在$(document).ready
  • 啊!我将它们放入 $(document).ready。这让我有些困惑。此事件中允许和不允许的内容...
【解决方案2】:

document.ready...

1) 在整个网页加载完毕后执行。

2) 通常,用于初始化 dom 元素(如 .click、.change、.select)上的事件。这是有道理的,因为您通常不能将事件附加到尚未加载的 dom 元素。

3) 通常,函数不会进入 document.ready。这是有道理的,因为函数通常被事件调用。

当然,凡事都有例外,但这些都是非常好的经验法则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 2017-08-20
    相关资源
    最近更新 更多