Perform client side validation for custom attribut

2019-01-01 11:39发布

问题:

I have created a Custom Validation Attribute:

public class FutureDateAttribute : ValidationAttribute
    {
        public override bool IsValid(object value) 
        {
            if (value == null|| (DateTime)value < DateTime.Now)
                return false;

            return true;
        }

    }

How can I get this to work on client side too with jquery?

回答1:

Here\'s how to proceed:

Start by defining the custom validation attribute:

public class FutureDateAttribute : ValidationAttribute, IClientValidatable
{
    public override bool IsValid(object value)
    {
        if (value == null || (DateTime)value < DateTime.Now)
            return false;

        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {
            ErrorMessage = this.ErrorMessage,
            ValidationType = \"futuredate\"
        };
    }
}

Notice how it implements IClientValidatable. Next we write our model:

public class MyViewModel
{
    [FutureDate(ErrorMessage = \"Should be in the future\")]
    public DateTime Date { get; set; }
}

Then a controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel
        {
            // intentionally put in the past
            Date = DateTime.Now.AddDays(-1)
        });
    }

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

and finally a view:

@using (Html.BeginForm())
{
    @Html.LabelFor(x => x.Date)
    @Html.TextBoxFor(x => x.Date)
    @Html.ValidationMessageFor(x => x.Date)
    <input type=\"submit\" value=\"OK\" />
}

The last part for the magic to happen is to define the custom adapter:

<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\">
    // we add a custom jquery validation method
    jQuery.validator.addMethod(\'greaterThan\', function (value, element, params) {
        if (!/Invalid|NaN/.test(new Date(value))) {
            return new Date(value) > new Date($(params).val());
        }
        return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val()));
    }, \'\');

    // and an unobtrusive adapter
    jQuery.validator.unobtrusive.adapters.add(\'futuredate\', { }, function (options) {
        options.rules[\'greaterThan\'] = true;
        options.messages[\'greaterThan\'] = options.message;
    });
</script>


回答2:

It took a little while since your question was asked, but if you still like metadata, and you\'re still open for simplified alternatives, you can solve your problem using following annotations:

[Required]
[AssertThat(\"Date > Now()\")]
public DateTime? Date { get; set; }

It works for both - server and client, out of the box. For further details take a look at ExpressiveAnnotations library.