3

I have 3 fields for date input:

<input type="text" id="passport-doi-1" name="passport-doi-1" placeholder="DD" maxlength="2">
<input type="text" id="passport-doi-2" name="passport-doi-2" placeholder="MM" maxlength="2">
<input type="text" id="passport-doi-3" name="passport-doi-3" placeholder="YYYY" maxlength="4">

How should I validate with jQuery Validate plugin that if date is input, then this is correct?

Looks like I should create groups of fields (to have only one error message) and then custom validation rule. But how it should look like?

Upd. I've tried to do the following, but it doesn't work:

$.validator.addMethod('validDate', function (value, element) {
  var dd = $("#passport-doi-dd").val();
  var mm = $("#passport-doi-mm").val();
  var yyyy = $("#passport-doi-yyyy").val();
  if (dd=="" && mm=="" && yyyy=="") return true;
  try {
    var date = new Date(yyyy,mm-1,dd,0,0,0,0);
    return mm===(date.getMonth()+1) && dd===date.getDate() && yyyy===date.getFullYear();
  }
  catch(er) {
    return false;
  }
}, 'Please use format DD MM YYYY.');

  ...
  rules: {
    "passport-doi-dd": {
      required: false,
      validDate: true,
      range: [1, 31]
    }, 
    "passport-doi-mm": {
      required: false,
      validDate: true,
      range: [1, 12]
    }, 
    "passport-doi-yyyy": {
      required: false,
      validDate: true,
      range: [1990, 2012]
    }
  },
  messages: {
    "passport-doi-dd": "Please use format DD MM YYYY.",
    "passport-doi-mm": "Please use format DD MM YYYY.",
    "passport-doi-yyyy": "Please use format DD MM YYYY."
  }
LA_
  • 19,823
  • 58
  • 172
  • 308

1 Answers1

2

You are on the right track-- You need to pass the Date constructor numbers instead of strings (val will return strings). You can also leverage the params argument to your custom rule to make it a bit more extensible (not specific to three fields with specific ids):

$.validator.addMethod("multidate", function (value, element, params) {
  var daySelector = params[0]
      , monthSelector = params[1]
      , yearSelector = params[2]
      , day = parseInt($(daySelector).val(), 10)
      , month = parseInt($(monthSelector).val(), 10)
      , year = parseInt($(yearSelector).val(), 10)
      , date = new Date(year, month, day);

  return (!$(daySelector).val() && !$(monthSelector).val() && !$(yearSelector).val()) || 
    !isNaN(date.getTime());

});


$(document).ready(function () {
  var dateFields = ["#passport-doi-1", "#passport-doi-2", "#passport-doi-3"];
  $("#dateform").validate({
    errorLabelContainer: "#errors",
    groups: {
      date: dateFields.join("")
    },
    rules: {
      "passport-doi-1": {
        multidate: dateFields
      },
      "passport-doi-2": {
        multidate: dateFields
      },
      "passport-doi-3": {
        multidate: dateFields
      }
    },
    messages: {
      "passport-doi-1": {
        multidate: "Please enter a valid date"
      },
      "passport-doi-2": {
        multidate: "Please enter a valid date"
      },
      "passport-doi-3": {
        multidate: "Please enter a valid date"
      }
    }
  });
});

I think the group option is only for grouping error messages (so you still have to define validation rules for each input).

Example: http://jsbin.com/oqawaz/9

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • Thanks, it works perfectly. Is there any way to refer to `groups` instead of `dateFields` creation and usage? – LA_ Feb 10 '12 at 18:04
  • @LA_: An easy way to do this would be to use the same array in `dateFields` and in assigning the `groups` property --see my updated answer. – Andrew Whitaker Feb 10 '12 at 18:13
  • Hmm, found one bug with this code - if user input day and month, but hasn't input year, then it is treated as valid (since year element is optional), but it shouldn't be - either full date or nothing. – LA_ Feb 10 '12 at 18:13
  • Yes, it is OK now. I've also added `range: [1930, 2012]` to the year field, otherwise even `1` was accepted. – LA_ Feb 10 '12 at 19:03
  • just now I've noticed that it accepts wrong dates like 33/13/2000. Looks like `!isNaN(date.getTime()` is incorrect way to verify dates - see http://stackoverflow.com/questions/10066005/how-to-allow-user-to-input-not-full-date-for-ex-without-date-and-month – LA_ Apr 09 '12 at 19:43
  • @LA_: It looks like validating whether an object is a date or not is not all that trivial: http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript – Andrew Whitaker Apr 14 '12 at 14:41
  • @LA_: Typo in `dateFields.join("")`. It must be `dateFields.join(" ")` (a space is missing) – TheStoryCoder Dec 01 '14 at 18:26
  • Check http://stackoverflow.com/questions/8098202/javascript-detecting-valid-dates if you want validation that also filters out dates like "february 31" – JasperZelf Oct 07 '15 at 10:22