简体   繁体   中英

ASP.NET MVC2 Custom jQuery validation: client -side

I want to create a validation rule for 2 date-pickers (startDate less then endDate).

I create a validation attribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class DateCompareAttribute : ValidationAttribute
{
    private const string _defaultErrorMessage = "'{0}' is less then '{1}'.";

    public DateCompareAttribute(string startDateProperty, string endDateProperty)
        : base(_defaultErrorMessage)
    {
        StartDateProperty = startDateProperty;
        EndDateProperty = endDateProperty;
    }

    public string StartDateProperty { get; private set; }
    public string EndDateProperty { get; private set; }


    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, StartDateProperty, EndDateProperty);
    }

    public override bool IsValid(object value)
    {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
        object startValue = properties.Find(StartDateProperty, true).GetValue(value);
        object endValue = properties.Find(EndDateProperty, true).GetValue(value);
        if (startValue.GetType() == typeof(DateTime?) && endValue.GetType() == typeof(DateTime?))
        {
            var start = ((DateTime?)startValue);
            var end = ((DateTime?)endValue);
            return (start.Value < end.Value);
        }
        return false;
    }
}

and added ti to my Dto:

[DateCompare("StartDate", "EndDate")]
public class QualificationInput{...}

I created a validator:

public class DateCompareValidator : DataAnnotationsModelValidator<DateCompareAttribute>
{
    string startField;
    private string endField;
    string _message;

    public DateCompareValidator(ModelMetadata metadata, ControllerContext context, DateCompareAttribute attribute)
        : base(metadata, context, attribute)
    {
        startField = attribute.StartDateProperty;
        endField = attribute.EndDateProperty;
        _message = attribute.ErrorMessage;
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = _message,
            ValidationType = "dateCompare"
        };
        rule.ValidationParameters.Add("startField", startField);
        rule.ValidationParameters.Add("endField", endField);

        return new[] { rule };
    }
}

And registered it in Global.asax.cs in Application_Start():

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DateCompareAttribute), typeof(DateCompareValidator));

In MicrosoftMvcJQueryValidation.js I have made this changes:

switch (thisRule.ValidationType)
{
.....
   case "dateCompare":
      __MVC_ApplyValidator_DateCompare(rulesObj,
      thisRule.ValidationParameters["startField"], thisRule.ValidationParameters["endField"]);
      break;
.....
}

function __MVC_ApplyValidator_DateCompare(object, startField, endField) {
    object["startField"] = startField;
    object["endField"] = endField;
}

jQuery.validator.addMethod("dateCompare", function(value, element, params) {
    if ($('#' + params["startField"]).val() < $('#' + params["endField"]).val())
    { return true; }
    return false;
}, jQuery.format("Error"));

But it doesn't work :( no client side validation on this type of rule (the others type like required works fine)

What I'm doing wrong?

You shouldn't need to change MicrosoftMvcJQueryValidation.js. I've recently had to address this issue myself and the following might help;

http://www.deepcode.co.uk/2010/08/custom-mvc-2-validation-using-jquery.html

I would copy paste the whole thing but I think it is best you just read Phil Haack's guide to custom validation in MVC

First, we need a model class. Let's do something simple like Customer:

public partial class Customer
{
    public string Name { get; set; }
    public int Age { get; set; }
}

then your validation logic

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
    class CustomerMetaData
    {
        [Required(ErrorMessage="You must supply a name for a customer.")]
        [StringLength(50, ErrorMessage = "A customer name cannot exceed 50 characters.")]
        public string Name { get; set; }
    }
}

then hook up your scripts

<script type="text/javascript" src="../../Scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="../../Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="../../Scripts/MicrosoftMvcJQueryValidation.js"></script>

Finally, somewhere before the start of your form tag, add the following markup to the view code:

<% Html.EnableClientValidation(); %>

It looks like you are applying the DateCompare attribute to the ViewModel class (rather than to properties). This is valid for server validation, but means that it doesn't get chance to opt in to client validation. See http://blogs.msdn.com/b/stuartleeks/archive/2010/08/06/asp-net-mvc-adding-client-side-validation-to-propertiesmustmatchattribute.aspx .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM