title: How to validate a date using 3 dropdowns( day, month, year ) using jquery unobtrusive validation?
body: <p>I have a model to validate and the problem is the date of birth field.
  It must be composed of 3 dropdowns (day, month, year).</p>
  
  <pre><code>&lt;div id="dob-editor-field" class="model-field-editor"&gt;
        @Html.LabelFor(m =&gt; m.DateOfBirth, new { @class = "label-div" })
        @Html.Telerik().DropDownList().Name("DobDay").BindTo((SelectList)ViewData["Days"]).HtmlAttributes(new {id = "DobDaySel"})
        @Html.Telerik().DropDownList().Name("DobMonth").BindTo((SelectList)ViewData["Months"]).HtmlAttributes(new { id = "DobMonthSel"})
        @Html.Telerik().DropDownList().Name("DobYear").BindTo((SelectList)ViewData["Years"]).HtmlAttributes(new { id = "DobYearSel" })
        @Html.ValidationMessageFor(m =&gt; m.DateOfBirth)
  &lt;/div&gt;
  </code></pre>
  
  <p>On the server side i do this</p>
  
  <pre><code>        [HttpPost]
          public ActionResult Register(RegistrationModel regInfo, int DobDay, int DobMonth, int DobYear)
          {
              SetRegisterViewData(DobDay, DobMonth, DobYear);
              if (DobDay == 0 || DobMonth == 0 &amp;&amp; DobYear == 0)
              {
                  ModelState.AddModelError("DateOfBirth", "Date of birth is required");
              }
              else
              {
                  DateTime dt = new DateTime(DobYear, DobMonth, DobDay);
                  long ticks = DateTime.Now.Ticks - dt.Ticks;
                  int years = new DateTime(ticks).Year;
                  if (years &lt; 18)
                  {
                      ModelState.AddModelError("DateOfBirth", "You must be at least 18");
                  }
              }            
              if (ModelState.IsValid)
              {
                  //register user
                  return RedirectToAction("Index", "Home");
              }
              return View(regInfo);
          }
  </code></pre>
  
  <p>Questions:</p>
  
  <ol>
  <li>Server side : how to make it better? (i am thinking of adding dob,
  month, and year properties RegistrationModel and add attribute on
  DateOfBirth to check those properties)</li>
  <li>Client side : i was looking at <a href="https://stackoverflow.com/questions/4747184/perform-client-side-validation-for-custom-attribute">Perform client side validation for custom attribute</a> but it got me confused.  What is the way to make it?</li>
  </ol>
  
  <p>LE: 
  I created a custom model binder for the date like this:</p>
  
  <pre><code>    public class DobModelBinder : DefaultModelBinder
      {
          protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
          {
              if (propertyDescriptor.Name == "DateOfBirth")
              {
                  DateTime dob = DateTime.MinValue;
                  var form = controllerContext.HttpContext.Request.Form;
                  int day = Convert.ToInt32(form["DobDay"]);
                  int month = Convert.ToInt32(form["DobMonth"]);
                  int year = Convert.ToInt32(form["DobYear"]);
                  if (day == 0 || month == 0 || year == 0)
                  {
                      SetProperty(controllerContext, bindingContext, propertyDescriptor, DateTime.MinValue);
                  }
                  else
                  {
                      SetProperty(controllerContext, bindingContext, propertyDescriptor, new DateTime(year, month, day));
                  }
              }
              else
              {
                  base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
              }
          }
      }
  </code></pre>
  
  <p>I registered it like this:</p>
  
  <pre><code>ModelBinders.Binders.Add(typeof(DateTime), new DobModelBinder());
  </code></pre>
  
  <p>I used it like this:</p>
  
  <pre><code>public ActionResult Register([ModelBinder(typeof(DobModelBinder))]RegistrationModel regInfo)
  </code></pre>
  
  <p>DateOfBirth binds well.</p>
  
  <p>LE2:</p>
  
  <p>I created validation attributes for the date of birth like this:</p>
  
  <pre><code> public override bool IsValid(object value)
      {
          DateTime date = Convert.ToDateTime(value);
          return date != DateTime.MinValue;
      }
  
      public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
      {
          yield return new ModelClientValidationRule
          {
              ErrorMessage = this.ErrorMessage,
              ValidationType = "dateRequired"
          };
      }
  }
  
  public class DateGraterThanEighteen : ValidationAttribute, IClientValidatable
  {
      public override bool IsValid(object value)
      {
          DateTime date = Convert.ToDateTime(value);
          long ticks = DateTime.Now.Ticks - date.Ticks;
          int years = new DateTime(ticks).Year;
          return years &gt;= 18;
      }
  
      public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
      {
          yield return new ModelClientValidationRule
          {
              ErrorMessage = this.ErrorMessage,
              ValidationType = "dateGraterThanEighteen"
          };
      }
  }
  </code></pre>
  
  <p>I applied attributes like this</p>
  
  <pre><code>        [DateGraterThanEighteen(ErrorMessage="You must be at least 18")]
          [DateRequired(ErrorMessage = "Date of birth is required")]
          public DateTime DateOfBirth { get; set; }
  </code></pre>
  
  <p>LE3:</p>
  
  <p>In the client side i do this:</p>
  
  <pre><code>      $(function () {
              jQuery.validator.addMethod('dobRequired', function (value, element, params) {
                  if (!/Invalid|NaN/.test(new Date(value))) {
                      return true;
                  }
                  else {
                      return false;
                  }
              }, '');
              jQuery.validator.unobtrusive.adapters.add('dateRequired', {}, function (options) {
                  options.rules['dobRequired'] = true;
                  options.messages['dobRequired'] = options.message;
              });
          });
  </code></pre>
  
  <p>Client validation doesn't seems to work.
  How can I fix it? I am kinda confused with the way these adapters work.</p>