user2415266 user2415266 - 1 month ago 9
Javascript Question

onchange + validation + enter key weird behaviour

I have a form with an input field for dates. The dates should be validated: only dates from today + maximum 3 years are allowed. If the date is valid, a modal will show, else there will be an alert with an error message.

Assuming somone changes the date to 26.10.2099:

Everything works as expected, if one leaves the input field (by clicking somewhere else with the mouse):


  • error message appears

  • date gets automatically changed back

  • no modal shows



BUT if one presses Enter instead of just leaving the input field, the following happens:


  • no error message shows

  • date gets automatically changed back

  • modal shows up



My thought is that changing the date back to its initial value causees the onchange event to be triggered again, and then the date is valid and the modal will show. But this is not the case for the first scenario. In the second scenario the event triggers twice SOMETIMES but not always.

You can tryout yourself here:
https://jsfiddle.net/6x9n53fx/3/

Or read the code below:

HTML:

<div class="container">
<form method="post" action="" enctype="multipart/form-data">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label for="review_date">Valid until *</label>
<input id="review_date" type="text" name="review_date" value="26.10.2016" class="form-control">
<p>Please set a validation date. (max 3 years)</p>
</div>
</div>
</div>
</form>
</div>
<!-- Modal -->
<div class="modal fade" id="info_modal" tabindex="-1" role="dialog" aria-labelledby="modal_title">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal_title">Dialog</h4>
</div>
<div class="modal-body">
<div class="form-group mbn">
<p class="mb10">Date successfully changed.</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button>
</div>
</div>
</div>
</div>


Javascript:

var datumfeld = $("#review_date");
var initialdatum = datumfeld.val();
var i = 0;
datumfeld.datepicker({
minDate: 0,
maxDate: "3y",
dateFormat: 'dd.mm.yy'
});
datumfeld.change(function() {
i++;
console.log('onchange triggered: ' + i);
if (validateDatum()) {
$("#info_modal").modal({
backdrop: "static",
keyboard: false
});
}
});

function validateDatum() {
var dateParts = datumfeld.val().split(".");
var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1));
if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) {
alert("Error: The date must not exceed 3 years from now.");
datumfeld.val(initialdatum);
return false;
}
if ((review_date - (new Date)) < 0) {
alert("Error: The date must not be in the past.");
datumfeld.val(initialdatum);
return false;
}
return true;
}

Answer

The problem from your code is when you press Enter your value != when you click else where. You can see it when you debug dateParts

When you enter example: 28.10.2099 and click away dateParts is ["28", "10", "2099"] But when enter example: 28.10.2099 and press ENTER dateParts is ["28", "10", "2019"] Here datepicker is validate the input field and set automaticly date to 28.10.2019 because you set maxDate to 3y.

So my solution is to bind keydown and bypass datepicker before it change the value automaticly.

Here is a link with working code: https://jsfiddle.net/95qbs86x/2/

Update: added code

var datumfeld = $("#review_date");
var initialdatum = datumfeld.val();
var i = 0;

// bind keydown event
datumfeld.on('keydown', function(e) {
  // when keydown is ENTER (13)
  if (e.keyCode == 13) {

    // trigger tab to hide datepicker
    var e = $.Event("keydown");
    e.which = 9; //tab 
    e.keyCode = 9;
    e.key = 'Tab';
    $(this).trigger(e);

    return false;
  }
}).datepicker({
  minDate: 0,
  maxDate: "3y",
  dateFormat: 'dd.mm.yy',
  onClose: function(){
    this.blur();
  }
}).on('change', function(e) {
  i++;
  console.log('onchange triggered: ' + i);
  if (validateDatum()) {
    $("#info_modal").modal({
      backdrop: "static",
      keyboard: false
    });
  }
});


function validateDatum() {
  var dateParts = datumfeld.val().split(".");
  console.log(dateParts);
  var review_date = new Date(dateParts[2], (dateParts[1] - 1), (parseInt(dateParts[0]) + 1));

  if (((new Date(review_date - (new Date()))).getFullYear() - 1970) > 2) {
    alert("Error: The date must not exceed 3 years from now.");
    datumfeld.val(initialdatum);
    return false;
  }
  if ((review_date - (new Date)) < 0) {
    alert("Error: The date must not be in the past.");
    datumfeld.val(initialdatum);
    return false;
  }
  return true;
}

Notice: Some code could be remove like: e.which = 9; e.key = 'Tab'; return false;

However to applying the same effect as click away, this line of code should be added:

onClose: function(){
  this.blur();
}

Some code was taken from this answere: Disable enter key in JQuery ui datepicker