MVC 3.0 - 不引人注目的客户端验证不适用于自定义属性

时间:2012-02-20 16:36:40

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

我是mvc 3.0和jquery的新手。我正在尝试使用自定义验证属性验证客户端和服务器端的“日期”。它在服务器端工作正常,但无法使其在客户端工作。

我正在使用mvc 3.0,jquery,IE 7.0。 我们需要在MVC 3.0中的global.ascx中注册任何东西吗?

请告诉我错误的地方。 TIA。

这是我的代码:

验证属性

 public class FutureDateAttribute : ValidationAttribute, IClientValidatable
 {
        private const string DateFormat = "mm/dd/yyyy";
        private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

        public DateTime Min { get; set; }
        public DateTime Max { get; set; }

        public FutureDateAttribute(string min)
            : base(DefaultErrorMessage)
        {
            Min = ParseDate(min);
            Max = DateTime.Now;
        }

        public override bool IsValid(object value)
        {
            if (value == null || !(value is DateTime))
            { return true; }
            DateTime dateValue = (DateTime)value;
            return Min <= dateValue && dateValue <= Max;
        }

        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
        }

        public class ModelClientValidationFutureDateRule : ModelClientValidationRule
        {
            public ModelClientValidationFutureDateRule(string errorMessage,
                DateTime min)
            {
                ErrorMessage = errorMessage;
                ValidationType = "futuredate";
                ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
                ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");
            }
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
            yield return rule;
        }

jquery的

(function ($) {
$.validator.addMethod('futuredate', function (value, element, param) {
    if (!value) return false;
    var min = $(param.min).val();
    var max = $(param.max).val();
    if (value < min || value > max) {
        return false;
    }
    return true;
});

$.validator.unobtrusive.adapters.add(
  'futuredate', ['min', 'max'],
  function (options) {
      var params = {
          min: options.params.min,
          max: options.params.max
      };

      options.rules['futuredate'] = params;
      if (options.message) {
          options.messages['futuredate'] = options.message;
      }
  });
} (jQuery)); 

参考

<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
 ///reference path="jquery-1.5.1.min.js" />
 ///reference path="jquery.validate.js" />
 ///reference path="jquery-ui-1.8.11.js" />
  ///reference path="jquery.validate.unobtrusive.min.js" />
 ///reference path="jquery.validate-vsdoc.js" />

型号:

[DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }

1 个答案:

答案 0 :(得分:2)

我可以在您的代码中看到一些问题。第一个:

ValidationParameters["min"] = min.ToString("mm/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("mm/dd/yyyy");

一定是:

ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");

因为mm表示分钟而非月份。

同样的评论:

private const string DateFormat = "mm/dd/yyyy";

必须是:

private const string DateFormat = "MM/dd/yyyy";

在客户端,您也有几个问题。在您的futuredate验证方法中,您似乎正在进行var min = $(param.min).val();转换为var min = $('12/31/1899').val();这显然没有多大意义。在能够比较它们之前,您必须将这些值解析为javascript Date个实例。

所以我建议你这样做:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
    (function ($) {
        var parseDate = function (str) {
            var m = str.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
            return (m) ? new Date(m[3], m[1] - 1, m[2]) : null;
        };

        $.validator.addMethod('futuredate', function (value, element, param) {
            if (!value) return false;

            var min = parseDate(param.min);
            var max = parseDate(param.max);
            var current = parseDate(value);

            if (min == null || max == null || current == null) {
                return false;
            }

            return (current >= min && current <= max);
        });

        $.validator.unobtrusive.adapters.add('futuredate', ['min', 'max'], function (options) {
            var params = {
                min: options.params.min,
                max: options.params.max
            };

            options.rules['futuredate'] = params;
            if (options.message) {
                options.messages['futuredate'] = options.message;
            }
        });
    } (jQuery));
</script>

@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.AssignedDate)
    @Html.EditorFor(x => x.AssignedDate)
    @Html.ValidationMessageFor(x => x.AssignedDate)
    <button type="submit">OK</button>
}

这是我用于测试用例的验证属性的完整代码:

public class FutureDateAttribute : ValidationAttribute, IClientValidatable
{
    private const string DateFormat = "MM/dd/yyyy";
    private const string DefaultErrorMessage = "'{0}' must be a date between {1:d} and current date.";

    public DateTime Min { get; set; }
    public DateTime Max { get; set; }

    public FutureDateAttribute(string min)
        : base(DefaultErrorMessage)
    {
        Min = ParseDate(min);
        Max = DateTime.Now;
    }

    public override bool IsValid(object value)
    {
        if (value == null || !(value is DateTime))
        { return true; }
        DateTime dateValue = (DateTime)value;
        return Min <= dateValue && dateValue <= Max;
    }

    private static DateTime ParseDate(string dateValue)
    {
        return DateTime.ParseExact(dateValue, DateFormat, System.Globalization.CultureInfo.InvariantCulture);
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Min);
    }

    public class ModelClientValidationFutureDateRule : ModelClientValidationRule
    {
        public ModelClientValidationFutureDateRule(string errorMessage,
            DateTime min)
        {
            ErrorMessage = errorMessage;
            ValidationType = "futuredate";
            ValidationParameters["min"] = min.ToString("MM/dd/yyyy");
            ValidationParameters["max"] = DateTime.Now.ToString("MM/dd/yyyy");
        }
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationFutureDateRule("Error message goes here", this.Min);
        yield return rule;
    }
}

模特:

public class MyViewModel
{
    [DisplayName("Assigned Date :")]
    [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
    [Required(ErrorMessage = "Assigned Date is required")]
    [DataType(DataType.Date)]
    [FutureDate("12/31/1899", ErrorMessage = "'{0}' must be a date between {1:d} and current date.")]
    public DateTime? AssignedDate { get; set; }
}

和控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel
        {
            AssignedDate = DateTime.Now.AddDays(2)
        });
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}