Javascript Datetimepicker в форме с динамическими элементами - PullRequest
1 голос
/ 18 октября 2019

Я использую http://eonasdan.github.io/bootstrap-datetimepicker/ в моем проекте. Это очень хорошо.

На одной странице у меня есть форма, где строки входных полей могут динамически добавляться или удаляться. В каждой строке есть ввод «startdate» и «enddate», называемый # substitute_0_start и # substitute_0_end . При запуске cloneNode () идентификаторы увеличиваются с помощью javascript. Т.е. после одного клона есть еще одна строка с # substitute_1_start и # substitute_1_end.

Мне нужно настроить параметры входов "startdate" и "enddate". Я использую цикл для перехода по каждой строке и настройки параметров. Это работает, как и ожидалось, вместо этого, если я пытаюсь установить minDate или maxDate соответствующего входа.

                 <div class="form-group col-md-3 col-xs-6">
                    <label for="substitute_0_start" class="control-label">ab dem</label>
                    <div class='input-group date substitute_start' id='substitute_0_start'>
                        <input type="text" class="form-control datepicker subst_start" name="substitute[0][start]" readonly="readonly"/>
                        <span class="input-group-addon">
                            <span class="glyphicon glyphicon-calendar"></span>
                        </span>
                    </div>
                </div>
                <div class="form-group col-md-3 col-xs-6">
                    <label for="substitute_0_end" class="control-label">bis zum</label>
                    <div class='input-group date substitute_end' id='substitute_0_end'>
                        <input type="text" class="form-control datepicker subst_end" name="substitute[0][end]" readonly="readonly"/>
                        <span class="input-group-addon">
                            <span class="glyphicon glyphicon-calendar"></span>
                        </span>
                    </div>
                </div>
          function callDatepickerAndSelect2(){
            for (a = 0; a <= i; a++){
                // WORKS!
                $('#substitute_'+a+'_start').datetimepicker({
                    format: "DD.MM.YYYY",
                    minDate: moment().add(1, 'minutes')
                });
                $('#substitute_'+a+'_end').datetimepicker({
                    format: "DD.MM.YYYY",
                    minDate: moment().add(1, 'days')
                });
                // WORKS NOT FOR CLONED ITEMS
                $("#interval_start").on("dp.change", function (e) {
                    $('.substitute_start').data("DateTimePicker").minDate(e.date);
                    $('.substitute_end').data("DateTimePicker").minDate(e.date);
                });
                $("#interval_end").on("dp.change", function (e) {
                    $('.substitute_start').data("DateTimePicker").maxDate(e.date);
                    $('.substitute_end').data("DateTimePicker").maxDate(e.date);
                });
                // THIS DOES NOT WORK!
                $("#substitute_"+a+"_start").on("dp.change", function (e) {
                    $("#substitute_"+ a +"_end").data("DateTimePicker").minDate(e.date);
                });
                $("#substitute_"+a+"_end").on("dp.change", function (e) {
                    $("#substitute_"+ a +"_start").data("DateTimePicker").maxDate(e.date);
                });
            };
        }

Каждый раз, когда срабатывает два последних dp.change (), я получаю ошибку Невозможно прочитать свойство 'minDate' из неопределенного или Невозможно прочитать свойство 'maxDate' из неопределенного .

Я не могу найти решение, как установить maxDate для # substitute_X_end , если # substitute_X_start изменено (и проклинать в другом направлении).

Кто-нибудь имеет представление о том, чтобы изначально установить maxDate / minDate для соответствующих входов, и если я сделал cloneNode () ??

EDIT Также я исследовал, что средняя частьне работает для клонированных элементов. Мне кажется, что клонированные элементы доступны для просмотра, но я не могу получить к ним доступ с помощью JavaScript. Я думаю, что мне нужно другое решение для клонирования всего DIV: - (

EDIT 2 Я установил скрипку. Оформить заказ здесь https://jsfiddle.net/qs8kf6wj/ (извините, datetimepicker делаетне работал там, не смог выяснить почему)

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Сначала я вижу некоторые проблемы с вашим кодом:

Вкл. callDatepickerAndSelect2 вы запрашиваете даты substitute_start и substitute_end вместо родителей, и вы связываетесь снова и сновадобавлены события для каждого нового элемента, это не очень хорошая идея

Так что я сделал несколько изменений в коде, надежда ясна:

1) Нет необходимости снова вызывать и перепривязывать каждый элементпросто позвоните текущему, который удерживается, на i

2) Разрешить изменять дату с полями только для чтения, это allowInputToggle и ignoreReadonly

3) Когда смена даты выполняется в родителях, вызовите функцию, которая обновляет childs (Подрерывы) updateRangeMin и updateRangeMax

4) Для новых childs отправьтетекущие даты выбраны так, что они могут начинаться с диапазонов, это то, что current_min и current_max означают

5) Не вызывайте JavaScript внутри HTML, это не так, но выглядит плохо

$(document).ready(function() {
  $("#interval_start").datetimepicker({
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $("#interval_end").datetimepicker({
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $("#interval_start").on("dp.change", function(e) {
    current_min = e.date;
    $("#interval_end")
      .data("DateTimePicker")
      .minDate(e.date);
    updateRangeMin(e.date);
  });

  $("#interval_end").on("dp.change", function(e) {
    current_max = e.date;
    $("#interval_start")
      .data("DateTimePicker")
      .maxDate(e.date);

    updateRangeMax(e.date);
  });

  callDatepickerAndSelect2(i);
});

function updateRangeMin(date) {
  for (let index = 0; index <= i; index++) {
    $("#substitute_" + index + "_start")
      .data("DateTimePicker")
      .minDate(date);
  }
}

function updateRangeMax(date) {
  for (let index = 0; index <= i; index++) {
    $("#substitute_" + index + "_end")
      .data("DateTimePicker")
      .maxDate(date);
  }
}
var i = 0;
var original = document.getElementById("substitute_0");
let current_min = null;
let current_max = null;

function duplicateElement() {
  var clone = original.cloneNode(true); // "deep" clone
  i++;
  clone.id = "substitute_" + i; // there can only be one element with an ID
  clone.childNodes;
  for (var input of $(".substitute_start", clone)) {
    input.id = clone.id + "_start";
  }
  for (var input of $(".substitute_end", clone)) {
    input.id = clone.id + "_end";
  }
  for (var input of $(".subst_text", clone)) {
    input.name = "substitute[" + i + "][text]";
  }
  for (var input of $(".subst_start", clone)) {
    input.name = "substitute[" + i + "][start]";
  }
  for (var input of $(".subst_end", clone)) {
    input.name = "substitute[" + i + "][end]";
  }

  original.parentNode.appendChild(clone);
  callDatepickerAndSelect2(i);
}

function removeElement(elementId) {
  var element = document.getElementById(elementId);
  element.parentNode.removeChild(element);
}

function callDatepickerAndSelect2(a) {
  let start_element = "#substitute_" + a + "_start";
  let end_element = "#substitute_" + a + "_end";

  $(start_element).datetimepicker({
    maxDate: current_max,
    minDate: current_min,
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $(end_element).datetimepicker({
    maxDate: current_max,
    minDate: current_min,
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $(start_element).on("dp.change", function(e) {
    $(end_element)
      .data("DateTimePicker")
      .minDate(e.date);
  });
  $(end_element).on("dp.change", function(e) {
    $(start_element)
      .data("DateTimePicker")
      .maxDate(e.date);
  });
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.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>


<div class="container">
  <h2>
    Main Interval
  </h2>
  This two dates are minDate and maxDate for all Sub-Intervals!
  <div class="row">
    <div class="form-group col-sm-6">
      <label for="interval_start" class="control-label">Interval start</label
          >
          <div class="input-group date" id="interval_start">
            <input
              type="text"
              class="form-control datepicker"
              name="interval_start"
              readonly="readonly"
            />
            <span class="input-group-addon">
              <span class="glyphicon glyphicon-calendar"></span>
            </span>
          </div>
        </div>
        <div class="form-group col-sm-6">
          <label for="interval_end" class="control-label">Interval end</label>
      <div class="input-group date" id="interval_end">
        <input type="text" class="form-control datepicker" name="interval_end" readonly="readonly" />
        <span class="input-group-addon">
              <span class="glyphicon glyphicon-calendar"></span>
        </span>
      </div>
    </div>
  </div>
  <h2>
    Sub-Intervals (n-times)
  </h2>
  <div class="row" style="border: 2px solid #0F0;">
    <div id="substitute_0" class="">
      <div class="panel-body">
        Each interval has to fit in the Main-Interval and has to fit: startdate
        < enddate and enddate> startdate
          <div class="form-group col-md-3 col-xs-6">
            <label for="substitute_0_start" class="control-label">ab dem</label
              >
              <div
                class="input-group date substitute_start"
                id="substitute_0_start"
              >
                <input
                  type="text"
                  class="form-control datepicker subst_start"
                  name="substitute[0][start]"
                  readonly="readonly"
                />
                <span class="input-group-addon">
                  <span class="glyphicon glyphicon-calendar"></span>
                </span>
              </div>
            </div>
            <div class="form-group col-md-3 col-xs-6">
              <label for="substitute_0_end" class="control-label"
                >bis zum</label
              >
              <div
                class="input-group date substitute_end"
                id="substitute_0_end"
              >
                <input
                  type="text"
                  class="form-control datepicker subst_end"
                  name="substitute[0][end]"
                  readonly="readonly"
                />
                <span class="input-group-addon">
                  <span class="glyphicon glyphicon-calendar"></span>
                </span>
              </div>
            </div>
          </div>
          <hr />
        </div>
      </div>
      <div class="row">
        <div class="input-group pull-right">
          add sub-interval
          <button
            type="button"
            class="btn btn-default"
            onclick="duplicateElement();"
          >
            <span class="glyphicon glyphicon-plus"></span>
          </button>
        </div>
      </div>
    </div>
0 голосов
/ 23 октября 2019

Немного лучше, без проблем minDate и maxDate И еще несколько улучшений!

$(document).ready(function() {
  $("#interval_start").datetimepicker({
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $("#interval_end").datetimepicker({
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $("#interval_start").on("dp.change", function(e) {
    current_min = e.date.startOf("day");
    $("#interval_end")
      .data("DateTimePicker")
      .minDate(e.date);
    updateRangeMin(e.date);
  });

  $("#interval_end").on("dp.change", function(e) {
    current_max = e.date.endOf("day");
    $("#interval_start")
      .data("DateTimePicker")
      .maxDate(e.date);

    updateRangeMax(e.date);
  });

  callDatepickerAndSelect2(i);
});

function updateRangeMin(date) {
  for (let index = 0; index <= i; index++) {
    var temp = new moment(date);
    if($("#substitute_" + index + "_start").data("DateTimePicker").maxDate().isBefore(date)){
       //for fixing maxDate is before minDate error
       $("#substitute_" + index + "_start").data("DateTimePicker").maxDate(temp.add(1825, "days"));
    }
    $("#substitute_" + index + "_start")
      .data("DateTimePicker")
      .minDate(date);
    if($("#substitute_" + index + "_end").data("DateTimePicker").maxDate().isBefore(date)){
                //for fixing maxDate is before minDate error
                $("#substitute_" + index + "_end").data("DateTimePicker").maxDate(temp.add(1825, "days"));
     }
     $("#substitute_" + index + "_end")
                .data("DateTimePicker")
                .minDate(date);
  }
}

function updateRangeMax(date) {
  for (let index = 0; index <= i; index++) {
    $("#substitute_" + index + "_end")
      .data("DateTimePicker")
      .maxDate(date);
    $("#substitute_" + index + "_start")
                .data("DateTimePicker")
                .maxDate(date);
  }
}
var i = 0;
var original = document.getElementById("substitute_0");
let current_min = null;
let current_max = null;

function duplicateElement() {
  var clone = original.cloneNode(true); // "deep" clone
  i++;
  clone.id = "substitute_" + i; // there can only be one element with an ID
  clone.childNodes;
  for (var input of $(".substitute_start", clone)) {
    input.id = clone.id + "_start";
  }
  for (var input of $(".substitute_end", clone)) {
    input.id = clone.id + "_end";
  }
  for (var input of $(".subst_text", clone)) {
    input.name = "substitute[" + i + "][text]";
  }
  for (var input of $(".subst_start", clone)) {
    input.name = "substitute[" + i + "][start]";
  }
  for (var input of $(".subst_end", clone)) {
    input.name = "substitute[" + i + "][end]";
  }
  for (var input of $(".subst_text", clone)) {
    input.value = "";
  }
  for (var input of $(".subst_start", clone)) {
    input.value = "";
  }
  for (var input of $(".subst_end", clone)) {
    input.value = "";
  }
  original.parentNode.appendChild(clone);
  callDatepickerAndSelect2(i);
}

function removeElement(elementId) {
  var element = document.getElementById(elementId);
  element.parentNode.removeChild(element);
}

function callDatepickerAndSelect2(a) {
  let start_element = "#substitute_" + a + "_start";
  let end_element = "#substitute_" + a + "_end";

  $(start_element).datetimepicker({
    maxDate: current_max,
    minDate: current_min,
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $(end_element).datetimepicker({
    maxDate: current_max,
    minDate: current_min,
    format: "DD.MM.YYYY",
    allowInputToggle: true,
    ignoreReadonly: true
  });

  $(start_element).on("dp.change", function(e) {
    $(end_element)
      .data("DateTimePicker")
      .minDate(e.date);
  });
  $(end_element).on("dp.change", function(e) {
    $(start_element)
      .data("DateTimePicker")
      .maxDate(e.date);
  });
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.37/css/bootstrap-datetimepicker.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.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>


<div class="container">
  <h2>
    Main Interval
  </h2>
  This two dates are minDate and maxDate for all Sub-Intervals!
  <div class="row">
    <div class="form-group col-sm-6">
      <label for="interval_start" class="control-label">Interval start</label
          >
          <div class="input-group date" id="interval_start">
            <input
              type="text"
              class="form-control datepicker"
              name="interval_start"
              readonly="readonly"
            />
            <span class="input-group-addon">
              <span class="glyphicon glyphicon-calendar"></span>
            </span>
          </div>
        </div>
        <div class="form-group col-sm-6">
          <label for="interval_end" class="control-label">Interval end</label>
      <div class="input-group date" id="interval_end">
        <input type="text" class="form-control datepicker" name="interval_end" readonly="readonly" />
        <span class="input-group-addon">
              <span class="glyphicon glyphicon-calendar"></span>
        </span>
      </div>
    </div>
  </div>
  <h2>
    Sub-Intervals (n-times)
  </h2>
  <div class="row" style="border: 2px solid #0F0;">
    <div id="substitute_0" class="">
      <div class="panel-body">
        Each interval has to fit in the Main-Interval and has to fit: startdate
        < enddate and enddate> startdate
          <div class="form-group col-md-3 col-xs-6">
            <label for="substitute_0_start" class="control-label">ab dem</label
              >
              <div
                class="input-group date substitute_start"
                id="substitute_0_start"
              >
                <input
                  type="text"
                  class="form-control datepicker subst_start"
                  name="substitute[0][start]"
                  readonly="readonly"
                />
                <span class="input-group-addon">
                  <span class="glyphicon glyphicon-calendar"></span>
                </span>
              </div>
            </div>
            <div class="form-group col-md-3 col-xs-6">
              <label for="substitute_0_end" class="control-label"
                >bis zum</label
              >
              <div
                class="input-group date substitute_end"
                id="substitute_0_end"
              >
                <input
                  type="text"
                  class="form-control datepicker subst_end"
                  name="substitute[0][end]"
                  readonly="readonly"
                />
                <span class="input-group-addon">
                  <span class="glyphicon glyphicon-calendar"></span>
                </span>
              </div>
            </div>
          </div>
          <hr />
        </div>
      </div>
      <div class="row">
        <div class="input-group pull-right">
          add sub-interval
          <button
            type="button"
            class="btn btn-default"
            onclick="duplicateElement();"
          >
            <span class="glyphicon glyphicon-plus"></span>
          </button>
        </div>
      </div>
    </div>
...