javascriptjqueryeonasdan-datetimepicker

form with dynamic time intervals and depending disabledTimeIntervals-settings


Using eonasdan/bootstrapdatetimepicker, I try to solve this:

How to set disabledTimeIntervals, minDate and maxDate for each dynamically created time-input-field? minDate and maxDate has to be set to the corresponding field, while disabledTimeIntervals has to be set to all fields, except the edited fields - also on every edit.

I do not have any glue to get this done.

Has anyone a solution for this?

$(document).ready(function() {
  $("#timeday0from").datetimepicker({
    format: "LT",
    allowInputToggle: true,
    ignoreReadonly: true
  });
  $("#timeday0until").datetimepicker({
    format: "LT",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $("#timeday0from").on("dp.change", function(e) {
    $("#timeday0until")
      .data("DateTimePicker")
      .minDate(e.date);
  });
  $("#timeday0until").on("dp.change", function(e) {
    $("#timeday0from")
      .data("DateTimePicker")
      .maxDate(e.date);
  });
});
var i = 0;
var day = "day_";
var original = document.getElementById(day + i);
function duplicateElement() {
  var clone = original.cloneNode(true);
  i++;
  clone.id = day + i; // there can only be one element with an ID
  clone.childNodes;
  for (var input of $(".timeday0from", clone)) {
    input.id = "time" + clone.id + "from";
  }
  for (var input of $(".timeday0until", clone)) {
    input.id = "time" + clone.id + "until";
  }
  for (var select of $(".timeday0type", clone)) {
    select.id = "time" + clone.id + "info";
  }
  for (var input of $(".timeday0from", clone)) {
    input.name = "time[" + day + "][" + i + "][from]";
  }
  for (var input of $(".timeday0until", clone)) {
    input.name = "time[" + day + "][" + i + "][until]";
  }
  for (var select of $(".timeday0type", clone)) {
    select.name = "time[" + day + "][" + i + "][type]";
  }
  for (var input of $(".timeday0from", clone)) {
    input.value = "";
  }
  for (var input of $(".timeday0until", clone)) {
    input.value = "";
  }
  for (var select of $(".timeday0type", clone)) {
    select.value = "";
  }
  original.parentNode.appendChild(clone);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/js/bootstrap-datetimepicker.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class="col-lg-6 col-md-12">
  <div class="well">
    <h3>Day</h3>
    <div class="row" id="day_0">
      <div class="form-group col-sm-4 col-xs-6">
        <label for="timeday0from" class="control-label">Interval starts</label>
        <div class='input-group date' id='timeday0from'>
          <input type="text" class="form-control datepicker timeday0from" name="time[day][0][from]" readonly="readonly"/>
          <span class="input-group-addon">
            <span class="glyphicon glyphicon-time"></span>
          </span>
        </div>
      </div>
      <div class="form-group col-sm-4 col-xs-6">
        <label for="timeday0until" class="control-label">Interval ends</label>
        <div class='input-group date' id='timeday0until'>
          <input type="text" class="form-control datepicker timeday0until" name="time[day][0][until]" readonly="readonly"/>
          <span class="input-group-addon">
            <span class="glyphicon glyphicon-time"></span>
          </span>
        </div>
      </div>
      <div class="form-group col-sm-4 col-xs-12">
        <label for="timeday0info" class="control-label">Interval-Option</label>
        <select name="time[day][0][info]" class="form-control timeday0type" id="timeday0info">
          <option>Bitte auswählen</option>
        </select>
      </div>
    </div>
  </div>
</div>
<button type="button" class="btn btn-default" onclick="duplicateElement();"><span class="glyphicon glyphicon-plus"></span></button>

Creating works. But I do not have any idea, how to set maxDate, minDate and disabledTimeIntervals (overlapping of ranges should prevented) on clone/remove of elemen and update of a time-field.


Solution

  • What a mess - but it works!

    $.fn.datetimepicker.defaults.tooltips = {
      today: 'Heute',
      clear: 'Auswahl leeren',
      incrementMinute: 'später',
      decrementMinute: 'früher',
      incrementHour: 'später',
      decrementHour: 'früher',
      pickHour: 'Stunde wählen',
      pickMinute: 'Minute wählen'
    };
    $.fn.datetimepicker.defaults.useCurrent = false;
    $.fn.datetimepicker.defaults.ignoreReadonly = true;
    $.fn.datetimepicker.defaults.allowInputToggle = true;
    $.fn.datetimepicker.defaults.locale = 'de';
    $.fn.datetimepicker.defaults.showClear = true;
    
    $(document).ready(function() {
      initDateTimePair('day',0);
      updateMin('day',0);
      updateMax('day',0);
    });
    
    var i = 0;
    var original = document.getElementById('day' +'_'+ i);
    
    function initDateTimePair(day, item){
      $("#time"+day+item+"from").datetimepicker({
        format: "LT",
        allowInputToggle: true,
        ignoreReadonly: true
      });
      $("#time"+day+item+"until").datetimepicker({
        format: "LT",
        allowInputToggle: true,
        ignoreReadonly: true
      });
    }
    function updateMax(day, item){
      $("#time"+day+item+"from").on("dp.change", function(e) {
        $("#time"+day+item+"until").data("DateTimePicker").minDate(e.date);
        if($('#time'+day+item+'until').data("DateTimePicker")){
          updateDisabledTimes(day, item);
        }
      });
    }
    function updateMin(day, item){
      $("#time"+day+item+"until").on("dp.change", function(e) {
        $("#time"+day+item+"from").data("DateTimePicker").maxDate(e.date);
        if($('#time'+day+item+'from').data("DateTimePicker")){
          updateDisabledTimes(day, item);
        }
      });
    }
    function initDisabledTimes(day, item){
      var arr = collectDisabledTime(day, null);
      $('#time'+day+item+'from').data("DateTimePicker").disabledTimeIntervals(arr);
      $('#time'+day+item+'until').data("DateTimePicker").disabledTimeIntervals(arr);
    }
    function updateDisabledTimes(day, item){
      for(l=0; l<=i; l++) {
        var arr = collectDisabledTime(day, item);
        if(l!=item){
          $('#time'+day+l+'from').data("DateTimePicker").disabledTimeIntervals(arr);
          $('#time'+day+l+'until').data("DateTimePicker").disabledTimeIntervals(arr);
        }
      }
    }
    function collectDisabledTime(day, item){
      var arr = [];
      for(j=0; j<=i; j++){
        if(j!=item){
          var from = $('#time'+day+j+'from').data("DateTimePicker");
          var until = $('#time'+day+j+'until').data("DateTimePicker");
          if(until !== undefined && until.date() !== null && from !== undefined && from.date() !== null){
            arr.push([$('#time'+day+j+'from').data("DateTimePicker").date().add(1,'minute'), $('#time'+day+j+'until').data("DateTimePicker").date().add(-1,'minute')]);
          }
        }
      }
      return arr;
    }
    function duplicateElement(day) {
      var clone = original.cloneNode(true);
      i++;
      clone.id = day + '_' + i; // there can only be one element with an ID
      clone.childNodes;
      for (var input of $(".time"+day+"from", clone)) {
        input.id = "time" + day + i + "from";
      }
      for (var input of $(".time"+day+"until", clone)) {
        input.id = "time" + day + i + "until";
      }
      for (var select of $(".time"+day+"type", clone)) {
        select.id = "time" + day + i + "info";
      }
      for (var input of $(".time"+day+"from", clone)) {
        input.name = "time[" + day + "][" + i + "][from]";
      }
      for (var input of $(".time"+day+"until", clone)) {
        input.name = "time[" + day + "][" + i + "][until]";
      }
      for (var select of $(".time"+day+"type", clone)) {
        select.name = "time[" + day + "][" + i + "][type]";
      }
      for (var input of $(".time"+day+"from", clone)) {
        input.value = "";
      }
      for (var input of $(".time"+day+"until", clone)) {
        input.value = "";
      }
      for (var select of $(".time"+day+"type", clone)) {
        select.value = "-1";
      }
      original.parentNode.appendChild(clone);
      initDateTimePair(day, i);
      updateMin(day, i);
      updateMax(day, i);
      initDisabledTimes(day, i);
      updateDisabledTimes(day, i);
      console.log($('#timeday'+i+'from').data("DateTimePicker").disabledTimeIntervals())
    }
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/locale/de.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/js/bootstrap-datetimepicker.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
    </head>
    <body>
    <div class="col-lg-6 col-md-12">
      <div class="well">
        <h3>Day</h3>
        <div class="row" id="day_0">
          <div class="form-group col-sm-4 col-xs-6">
            <label for="timeday0from" class="control-label">Interval starts</label>
            <div class='input-group date' id='timeday0from'>
              <input type="text" class="form-control datepicker timedayfrom" name="time[day][0][from]" readonly="readonly"/>
              <span class="input-group-addon">
                <span class="glyphicon glyphicon-time"></span>
              </span>
            </div>
          </div>
          <div class="form-group col-sm-4 col-xs-6">
            <label for="timeday0until" class="control-label">Interval ends</label>
            <div class='input-group date' id='timeday0until'>
              <input type="text" class="form-control datepicker timedayuntil" name="time[day][0][until]" readonly="readonly"/>
              <span class="input-group-addon">
                <span class="glyphicon glyphicon-time"></span>
              </span>
            </div>
          </div>
          <div class="form-group col-sm-4 col-xs-12">
            <label for="timeday0info" class="control-label">Interval-Option</label>
            <select name="time[day][0][info]" class="form-control timedaytype" id="timeday0info">
              <option value="-1">Bitte auswählen</option>
            </select>
          </div>
        </div>
      </div>
    </div>
    <button type="button" class="btn btn-default" onclick="duplicateElement('day');"><span class="glyphicon glyphicon-plus"></span></button>