【问题标题】:MVC custom validation: compare two datesMVC 自定义验证:比较两个日期
【发布时间】:2011-10-24 21:48:38
【问题描述】:

我创建了一个自定义 ValidationAttribute,它比较两个日期并确保第二个日期大于第一个日期:

public sealed class IsDateAfter : ValidationAttribute, IClientValidatable
{
    private readonly string testedPropertyName;
    private readonly bool allowEqualDates;

    public IsDateAfter(string testedPropertyName, bool allowEqualDates = false)
    {
        this.testedPropertyName = testedPropertyName;
        this.allowEqualDates = allowEqualDates;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName);
        if (propertyTestedInfo == null)
        {
            return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName));
        }

        var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

        if (value == null || !(value is DateTime))
        {
            return ValidationResult.Success;
        }

        if (propertyTestedValue == null || !(propertyTestedValue is DateTime))
        {
            return ValidationResult.Success;
        }

        // Compare values
        if ((DateTime)value >= (DateTime)propertyTestedValue)
        {
            if (this.allowEqualDates)
            {
                return ValidationResult.Success;
            }
            if ((DateTime)value > (DateTime)propertyTestedValue)
            {
                return ValidationResult.Success;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = this.ErrorMessageString,
            ValidationType = "isdateafter"
        };
        rule.ValidationParameters["propertytested"] = this.testedPropertyName;
        rule.ValidationParameters["allowequaldates"] = this.allowEqualDates;
        yield return rule;
    }

CalendarEntry 类: ...

public virtual DateTime StartDate { get; set; }

[IsDateAfter("StartDate", true, ErrorMessage="End date needs to be after start date")]
public virtual DateTime EndDate { get; set; }

查看:

$.validator.unobtrusive.adapters.add(
    'isdateafter', ['propertytested', 'allowequaldates'], function (options) {
    options.rules['isdateafter'] = options.params;
    options.messages['isdateafter'] = options.message;
});
$.validator.addMethod("isdateafter", function(value, element, params) {
    alert(params.propertytested);
    var startdatevalue = $('input[name="' + params.propertytested + '"]').val();
    if (!value || !startdatevalue) return true;
    return (params.allowequaldates) ? Date.parse(startdatevalue) <= Date.parse(value) : Date.parse(startdatevalue) < Date.parse(value);
}, '');

CalendarEntry 未包含在另一个类中时,这可以正常工作。但是,当我使用这样的视图模型时:

    public class TrainingDateEditViewModel
    {
        #region Properties

        /// <summary>
        /// Gets or sets CalendarEntry.
        /// </summary>
        public CalendarEntry CalendarEntry { get; set; }
....

客户端验证不再起作用,因为生成的 html 输出是这样的:

<input type="text" value="" name="CalendarEntry.EndDate" id="CalendarEntry_EndDate" data-val-isdateafter-propertytested="StartDate" data-val-isdateafter-allowequaldates="True" data-val-isdateafter="End date needs to be after start date" data-val="true">

还有

data-val-isdateafter-propertytested="StartDate" and IT SHOULD BE: "CalendarEntry.StartDate".

我将如何使它知道绑定到“CalendarEntry.StartDate” rule.ValidationParameters["propertytested"] = this.testedPropertyName; // 这里应该是全名???怎么样??

谢谢

【问题讨论】:

  • 感谢您提供此代码,我已在验证中成功实现它
  • 也感谢您的更新,感谢@counsellorben 的更新。
  • 使用Attribute为您的课程添加后缀可能是个好主意

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


【解决方案1】:

您需要修改您的客户端脚本以检查被测试元素的前缀,并将前缀(如果有)添加到您的选择器,如下所示:

$.validator.addMethod("isdateafter", function(value, element, params) {
    var parts = element.name.split(".");
    var prefix = "";
    if (parts.length > 1)
        prefix = parts[0] + ".";
    var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val();
    if (!value || !startdatevalue) 
        return true;    
    return (params.allowequaldates) ? Date.parse(startdatevalue) <= Date.parse(value) :
        Date.parse(startdatevalue) < Date.parse(value);
});

【讨论】:

    【解决方案2】:

    不要忘记在此代码中包含客户端。我花了好几个小时才发现它不见了!

    (function ($) {
    
      // your code here..
    
    })(jQuery);
    

    【讨论】:

      【解决方案3】:

      只是为了修复coulorben javascript 中的一个小错误:“(params.allowequaldates)”将被解释为一个字符串(其值为“False”或“True”),但该字符串将始终被评估为真,因此总是允许相同的日期。 如果您还希望允许对象的嵌套层数超过 1 层,那么您将获得:

      $.validator.addMethod("isdateafter", function(value, element, params) {
          var parts = element.name.split(".");
          var prefix = "";
          for (var i = 0; i < parts.length - 1; i++)
             prefix = parts[i] + ".";
          var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val();
          if (!value || !startdatevalue) 
              return true;    
          var allowequal = params.allowequaldates.toLowerCase === "true";
          return allowequal ? Date.parse(startdatevalue) <= Date.parse(value) :
              Date.parse(startdatevalue) < Date.parse(value);
      });
      

      【讨论】:

        【解决方案4】:

        在最后一个答案中,对 toLowerCase 的调用缺少一些括号,这是一个已准备好文档和 $.validator.unobtrusive...-part 的更新版本:

        $(function () {
            $.validator.addMethod("isdateafter", function(value, element, params) {
                var parts = element.name.split(".");
                var prefix = "";
                for (var i = 0; i < parts.length - 1; i++) {
                    prefix = parts[i] + ".";
                }
        
                var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val();
        
                if (!value || !startdatevalue) return true;    
        
                var allowequal = params.allowequaldates.toLowerCase() === "true";
                return allowequal ? Date.parse(startdatevalue) <= Date.parse(value) :
                    Date.parse(startdatevalue) < Date.parse(value);
            });
            $.validator.unobtrusive.adapters.add('isdateafter', 
                ['propertytested', 'allowequaldates'], 
                function (options) {
                    options.rules['isdateafter'] = options.params;
                    options.messages['isdateafter'] = options.message;
                });
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-20
          • 2011-12-14
          • 1970-01-01
          • 2016-12-12
          • 1970-01-01
          • 2019-03-18
          相关资源
          最近更新 更多