2

So with this code I'm trying (not done by me but it's a bit different) to do a date of birth select with 3 selects, 1 for day, 1 for month and 1 for year, but whenever the user chooses for ex 30 for day and then chooses February it displays an error using setCustomValidity and reportValidity but it does not work when I choose 29 day then February then choose a non leap year like 2022, its does not show the error.

var Days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // index => month [0-11]
$(document).ready(function() {
  var option = '<option id="dayOption" selected disabled value="day">Day</option>';
  var selectedDay = "day";
  for (var i = 1; i <= Days[0]; i++) { //add option days
    option += '<option value="' + i + '">' + i + '</option>';
  }
  $('#day').append(option);
  $('#day').val(selectedDay);


  var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

  var option = '<option selected disabled value="month">Month</option>';
  var selectedMon = "month";
  for (var i = 1; i <= 12; i++) {
    option += '<option value="' + i + '">' + months[i - 1] + '</option>';
  }
  $('#month').append(option);
  $('#month').val(selectedMon);

  var d = new Date();
  var option = '<option selected disabled value="year">Year</option>';
  selectedYear = "year";
  for (var i = d.getFullYear(); i >= 1910; i--) { // years start i
    option += '<option value="' + i + '">' + i + '</option>';
  }
  $('#year').append(option);
  $('#year').val(selectedYear);
});

function isLeapYear(year) {
  if (year == "year") {
    return true;
  } else {
    year = parseInt(year);
    if (year % 4 != 0) {
      return false;
    } else if (year % 400 == 0) {
      return true;
    } else if (year % 100 == 0) {
      return false;
    } else {
      return true;
    }
  }

}


function change_month(select) {
  var day = $('#day');
  var val = $(day).val();
  $(day).empty();
  var option = '<option id="dayOption" selected disabled value="day">Day</option>';
  var month = parseInt($(select).val()) - 1;
  for (var i = 1; i <= Days[month]; i++) { //add option days
    if (val == i) {
      option += '<option selected value="' + i + '">' + i + '</option>';
    } else {
      option += '<option value="' + i + '">' + i + '</option>';
    }

  }
  $(day).append(option);
  if (val > Days[month]) {
    dayOption = $('#dayOption');
    dayOption.removeAttr("disabled", false);
    dayOption.removeAttr("selected", false);

    dayOption.attr("selected", true);
    dayOption.attr("disabled", true);

    day.get(0).setCustomValidity("Wrong day");
    day.get(0).reportValidity();
  } else {
    day.get(0).setCustomValidity("");
  }
}


function change_year(select) {
  if (isLeapYear($(select).val())) {
    Days[1] = 29;
  } else {
    Days[1] = 28;
  }


  month = $("#month").val();
  if (month == 2) {
    var day2 = $('#day');
    var val = $(day).val();
    $(day2).empty();
    var option = '<option id="dayOption" selected disabled value="day">Day</option>';
    for (var i = 1; i <= Days[1]; i++) { //add option days
      if (val == i) {
        option += '<option selected value="' + i + '">' + i + '</option>';
      } else {
        option += '<option value="' + i + '">' + i + '</option>';
      }
    }
    $(day2).append(option);

    if (month > Days[1]) {
      day2.get(0).setCustomValidity("Wrong day");
      day2.get(0).reportValidity();

      dayOption = $('#dayOption');
      dayOption.removeAttr("disabled", false);
      dayOption.removeAttr("selected", false);

      dayOption.attr("selected", true);
      dayOption.attr("disabled", true);

    } else {
      day2.get(0).setCustomValidity("");
    }


  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form class="container">
  <SELECT id="day" name="dd"></SELECT>
  <SELECT id="month" name="mm" onchange="change_month(this)"></SELECT>
  <SELECT id="year" name="yyyy" onchange="change_year(this)"></SELECT>
</form>
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • if you select the year first (2022), then you select "May", choose "29" and then change month to "February", the message is shown. – GrafiCode Jun 03 '22 at 19:59
  • But I want to work in both ways or at least work in this order: dd-mm-YY – Diogo Carvalho Jun 03 '22 at 20:01
  • fact is, when you change the year as last choice, after selecting any day AND February as month, the function `change_year` handles that option in a "special" way, you can see there's a specific condition `if (month == 2)`. – GrafiCode Jun 03 '22 at 20:09
  • `removeAttr` takes one parameter: the name of the attribute to remove. You should not use true and false with `attr` and Boolean attributes like `selected` and `disabled`; use `prop` or the name of the attribute (e.g., `.prop('selected', true)` or `.attr('selected', 'selected')`). See [prop() vs attr()](https://stackoverflow.com/q/5874652/215552) – Heretic Monkey Jun 03 '22 at 20:10
  • How would `month`, the value of the month (2) ever be higher than the number of days in the month (28 or 29) (`if (month > Days[1]) {`)? – Heretic Monkey Jun 03 '22 at 20:18

2 Answers2

2

We do NOT need leap year tests - just create a date with what is entered and test the year month and day are the same. OR change the number of days depending on the month chosen

This code does not need to give errors, the user cannot select a wrong date

Also it can generate month names in any valid locale

const isValid = (year,month,day) => {
  const date = new Date(year,month,day,15,0,0,0)
  return date.getMonth() === month && date.getDate() === day; // valid date
};
const getLastDay = (year, month) => new Date(year,month+1,0,15,0,0,0).getDate();
  

$(function() {
  const $year = $('#year');
  const $month = $('#month');
  const $day = $('#day');
  const date = new Date();
  date.setDate(15); // arbitrary, but not 1 
  $month.append(
    Array.from({
      length: 12
    }).map((_, i) => {
      date.setMonth(i);
      return `<option value="${i}">${date.toLocaleString("en-US",{ month: "long" })}</option>`;
    })
  );

  const endYear = date.getFullYear();
  const years = [];
  for (let i = endYear, n = endYear - 110; i >= n; i--) years.push(`<option value="${i}">${i}</option>`);
  $year.append(years.join(""));

  $day.append(
    Array.from({
      length: 31
    }).map((_, i) => `<option value="${i+1}">${i+1}</option>`)
  );
  const $days = $day.find("option");

  $('#day, #month, #year').on("change",(e) => {
    const month = +$month.val();
    const year = +$year.val();
    const day = +$day.val();
    if (day === null || month === null || year === null) return; // nothing selected
    if (isValid(year,month,day)) return; // ok date 
    const lastDay = getLastDay(year,month)
    if (day>lastDay) $day.val("day"); // reset
    for (let i = lastDay; i<=32; i++) $days.eq(i).prop("disabled",i>lastDay); // toggle disabled
  })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form class="container">
  <select id="day" name="dd">
    <option selected disabled value="day">Day</option>
  </select>
  <select id="month" name="mm">
    <option selected disabled value="month">Month</option>
  </select>
  <select id="year" name="yyyy"><option selected disabled value="year">Year</option></select>
</form>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
1

var Days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // index => month [0-11]
$(document).ready(function() {
  var option = '<option id="dayOption" selected disabled value="day">Day</option>';
  var selectedDay = "day";
  for (var i = 1; i <= Days[0]; i++) { //add option days
    option += '<option value="' + i + '">' + i + '</option>';
  }
  $('#day').append(option);
  $('#day').val(selectedDay);


  var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

  var option = '<option selected disabled value="month">Month</option>';
  var selectedMon = "month";
  for (var i = 1; i <= 12; i++) {
    option += '<option value="' + i + '">' + months[i - 1] + '</option>';
  }
  $('#month').append(option);
  $('#month').val(selectedMon);

  var d = new Date();
  var option = '<option selected disabled value="year">Year</option>';
  selectedYear = "year";
  for (var i = d.getFullYear(); i >= 1910; i--) { // years start i
    option += '<option value="' + i + '">' + i + '</option>';
  }
  $('#year').append(option);
  $('#year').val(selectedYear);
});

function isLeapYear(year) {
  if (year == "year") {
    return true;
  } else {
    year = parseInt(year);
    if (year % 4 != 0) {
      return false;
    } else if (year % 400 == 0) {
      return true;
    } else if (year % 100 == 0) {
      return false;
    } else {
      return true;
    }
  }

}


function change_month(select) {
  var day = $('#day');
  var val = $(day).val();
  $(day).empty();
  var option = '<option id="dayOption" selected disabled value="day">Day</option>';
  var month = parseInt($(select).val()) - 1;
  for (var i = 1; i <= Days[month]; i++) { //add option days
    if (val == i) {
      option += '<option selected value="' + i + '">' + i + '</option>';
    } else {
      option += '<option value="' + i + '">' + i + '</option>';
    }

  }
  $(day).append(option);
  if (val > Days[month]) {
    dayOption = $('#dayOption');
    dayOption.removeAttr("disabled", false);
    dayOption.removeAttr("selected", false);

    dayOption.attr("selected", true);
    dayOption.attr("disabled", true);

    day.get(0).setCustomValidity("Wrong day");
    day.get(0).reportValidity();
  } else {
    day.get(0).setCustomValidity("");
  }
}


function change_year(select) {
  if (isLeapYear($(select).val())) {
    Days[1] = 29;
  } else {
    Days[1] = 28;
  }


  month = $("#month").val();
  if (month == 2) {
    var day2 = $('#day');
    var val = $(day).val();
    $(day2).empty();
    var option = '<option id="dayOption" selected disabled value="day">Day</option>';
    for (var i = 1; i <= Days[1]; i++) { //add option days
      if (val == i) {
        option += '<option selected value="' + i + '">' + i + '</option>';
      } else {
        option += '<option value="' + i + '">' + i + '</option>';
      }
    }
    $(day2).append(option);

    if (val > Days[1]) {
      day2.get(0).setCustomValidity("Wrong day");
      day2.get(0).reportValidity();

      dayOption = $('#dayOption');
      dayOption.removeAttr("disabled", false);
      dayOption.removeAttr("selected", false);

      dayOption.attr("selected", true);
      dayOption.attr("disabled", true);

    } else {
      day2.get(0).setCustomValidity("");
    }


  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form class="container">
  <SELECT id="day" name="dd"></SELECT>
  <SELECT id="month" name="mm" onchange="change_month(this)"></SELECT>
  <SELECT id="year" name="yyyy" onchange="change_year(this)"></SELECT>
</form>

I have updated one line.

In function change_year

if (month > Days[1]) {

to

if (val > Days[1]) {

toptecshare
  • 166
  • 2
  • 24