1
votes

I'd like to enforce dates in the form dd-mmm-yyyy. I'm using the following post as a guide:

http://blogs.msdn.com/b/stuartleeks/archive/2011/01/25/asp-net-mvc-3-integrating-with-the-jquery-ui-date-picker-and-adding-a-jquery-validate-date-range-validator.aspx

Problem: The ValidationMessageFor text will not display (both on postback and client side). Any advice?

Update:

By including @Darin-Demintrov's answer, the code in this question now works. Note that the validation message persists after a date is picked. To solve this issue, one must handle the DatePicker onChange() event per my answer below.

View model property:

    [Required(ErrorMessage = "* required")]
    [Display(Name = "Event Date")]
    [PpcDate]
    public DateTime EventDate { get; set; }

PpcDate ValidationAttribute Class:

public class PpcDateAttribute : ValidationAttribute, IClientValidatable, IMetadataAware
{
    /// <summary>
    /// Any valid DateTime is fine; 
    /// the regex verification only happens on the client
    /// </summary>
    public override bool IsValid(object value)
    {
        if (value == null || (value is DateTime))
            return true;
        else
            return false;
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format("{0} must be in the form dd-mmm-yyyy", name);
    }

    #region IClientValidatable Members

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

    #endregion

    #region IMetadataAware Members

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.DataTypeName = "Date";
    }

    #endregion
}

The View:

@Html.EditorFor(model => model.EventDate)
@Html.ValidationMessageFor(model => model.EventDate)

And the javascript hookup:

(function ($) {
    // The validator function
    $.validator.addMethod('ppcdate', function (value) {
        if (!value) {
            return true;
        } else {
            return /^\d{2}-\w{3}-\d{4}$/.test(value);
        }

    });

    // The adapter to support ASP.NET MVC unobtrusive validation
    $.validator.unobtrusive.adapters.add('ppcdate', [], function (options) {

        // EDIT: Add next line per Darin's answer below.  
        options.rules['ppcdate'] = true;

        if (options.message) {
            options.messages['ppcdate'] = options.message;
        }
    });
} (jQuery));

The resulting html sure looks right?

Note that the data-val-ppcdate attribute appears as expected...

<div class="t-widget t-datepicker">
  <div class="t-picker-wrap">
    <input autocomplete="off" class="t-input valid" data-val="true" data-val-ppcdate="Event Date must be in the form dd-mmm-yyyy" data-val-required="* required" id="EventDate" name="EventDate" value="28-Sep-2011" type="text">
    <span class="t-select">
      <span class="t-icon t-icon-calendar" title="Open the calendar">Open the calendar</span>  
    </span>
  </div>
</div>
<span class="field-validation-valid" data-valmsg-for="EventDate" data-valmsg-replace="true"></span>

Any advice?

3
i'm confused, shouldn't you view look like @Html.EditorFor(model => model.EventDate , new { selectedDate = DateTime.Now }) as the validation attribute is on the EventDate propertyRafay
That's a good eye. I updated the question. ReceivedDate is the next property down. I was trying to keep the example concise and focus on just one property.Brett

3 Answers

3
votes

You forgot to register the rule and your custom ppcdate validation method never fires:

$.validator.unobtrusive.adapters.add('ppcdate', [], function (options) {
    if (options.message) {
        // This is what associates the adapter with the custom validation method
        options.rules['ppcdate'] = options.params;
        options.messages['ppcdate'] = options.message;
    }
});

Here's a full example.

0
votes

Load up fiddler and see if your CSS file is not loading. I know the summary won't show if the CSS doesn't load so I have to assume the same applies to individual validation items.

0
votes

Darin's answer explains why the rule was not firing. One other quirk is that I had to force validation when the the DatePicker onChange() event fires. Otherwise, the validation only fires when the user clicks or tabs directly on the date input. If they open and close the DatePicker, the validation message persists, even though the date is valid. I'm using Telerik controls, so it looks like this:

Date.ascx file (Date control):

<%= Html.Telerik().DatePickerFor(m => m)
    .Format("dd-MMM-yyyy")
    .Value(ViewData["selectedDate"] as DateTime?)
    .ClientEvents(e => { e.OnChange("PPC_validateTelerikDate"); })
%>

Javascript

/*****************************************************************************
    PPC_validateTelerikDate()
    Force validation to run on the target input.  
    This function allows one to validate when the date picker changes.
    Otherwise, validation only runs when clicking the input element directly
    or tabbing through.
*****************************************************************************/
function PPC_validateTelerikDate(e) {
    // get the form validation object
    var val = $(e.target.form).validate();
    // now validate the target
    val.element($(e.target));
}