jQuery UI datepicker с ручным вводом и динамической минимальной датой - PullRequest
0 голосов
/ 18 марта 2019

У меня есть несколько сборщиков дат на моей странице, которые могут быть заполнены сборщиком или введением вручную. Есть несколько правил, которые должны работать с этими датчиками, но я понятия не имею, как решить это динамически.

Задача 1
Дата 2 не должна быть раньше даты 1. Дата 3 не должна быть раньше 1 и 2.
На данный момент это работает для выбора даты, но не для ручного ввода. Если дата вводится вручную и предшествует минимальной дате, поле следует оставить пустым.

Задача 2
Если первая дата изменится (на более раннюю, как и раньше), минимальная дата для второй даты также должна быть обновлена.
То же самое относится и к третьему сборщику даты.

На этой странице может быть 1-x указатель даты!

let d = new Date();
let nextValidDate = d.getDate() + "." + (d.getMonth() + 1) + "." + d.getFullYear();

$(document).on("blur change", ".datepicker", function () {
    nextValidDate = $(this).datepicker("getDate");
});

$(document).on('focus', '.datepicker',
    function () {
        $(this).datepicker({
            numberOfMonths: 1,
            firstDay: 1,
            changeMonth: true,
            changeYear: true,
            dateFormat: 'dd.mm.yy',
            minDate: nextValidDate
        });

        $(this).datepicker('show');
    });


$(document).on('blur', '.datepicker', function () {
    if ($(this).val().length >= 2) {
        parseInputDate(this);
    }
});



function parseInputDate(elm) {
    var currDate = new Date(),
        monDt = (('0' + currDate.getMonth() + 1).slice(-2) + ('0' + currDate.getDate()).slice(-2)), // get current month+date to compare
        inputVal = $(elm).val().match(/\d{2}/gi); // split date components into array of [dd,mm,yy,yy]

    // another date validation, by comparing parameters and date object result 
    var isValidDate = function (yyyy, mm, dd) {
        var dt = new Date(yyyy, parseInt(mm, 10) - 1, dd);
        return (dt.getFullYear() + '-' + ('0' + (dt.getMonth() + 1)).slice(-2) + '-' + ('0' + dt.getDate()).slice(-2)) == yyyy + '-' + mm + '-' + dd;
    }

    if (inputVal != null && inputVal.length >= 2) {
        var year = currDate.getFullYear();

        if (monDt > (inputVal[1] + inputVal[0])) year++;
        // generate formatted text based on date component count
        // add date validation to catch invalid dates using (new Date('yyyy-mm-dd')).getTime() which will return NaN on invalid date

        var result = (inputVal.length == 2 && isValidDate(year, inputVal[1], inputVal[0]) && inputVal[0] + '.' + inputVal[1] + '.' + year) ||
            (inputVal.length == 3 && isValidDate('20' + inputVal[2], inputVal[1], inputVal[0]) && inputVal[0] + '.' + inputVal[1] + '.20' + inputVal[2]) ||
            (inputVal.length == 4 && isValidDate(inputVal[2] + inputVal[3], inputVal[1], inputVal[0]) && inputVal[0] + '.' + inputVal[1] + '.' + inputVal[2] + inputVal[3]) ||
            ''; // set empty on invalid dates

        $(elm).val(result);
        nextValidDate = result;
    } else {
        $(elm).val('')
    };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>

<div>
  <label for="date1">Date 1:</label>
  <input type="text" class="datepicker" id="date1">
</div>
<div>
  <label for="date2">Date 2:</label>
  <input type="text" class="datepicker" id="date2">
</div>
<div>
  <label for="date3">Date 3:</label>
  <input type="text" class="datepicker" id="date3">
</div>

1 Ответ

1 голос
/ 19 марта 2019

Рассмотрим этот пример: http://jqueryui.com/datepicker/#date-range

Мы можем настроить ваш код так:

$(function() {
  var dateFormat = 'dd.mm.yy';

  function getDate(el) {
    var date;
    try {
      date = $.datepicker.parseDate(dateFormat, el.value);
    } catch (error) {
      date = null;
    }
    return date;
  }

  function checkMinDate(el) {
    var date = getDate(el);
    var minDate = $(el).datepicker("option", "minDate");
    var test;
    try {
      test = (date >= minDate);
    } catch (error) {
      test = false;
    }
    return test;
  }

  $(".datepicker").datepicker({
    numberOfMonths: 1,
    firstDay: 1,
    changeMonth: true,
    changeYear: true,
    dateFormat: dateFormat,
    minDate: 0
  }).on("change", function(e) {
    e.preventDefault();
    var td = getDate(this);
    var dpid = $(this).attr("id");
    var dpi = parseInt(dpid.slice(dpid.indexOf("-") + 1));
    $("#date-" + (dpi + 1)).prop("disabled", false).datepicker("option", {
      minDate: td,
      defaultDate: td
    });
    if (!checkMinDate(this)) {
      this.value = "";
      return false;
    }
    return true;
  });
  $(".datepicker:not(:eq(0))").prop("disabled", true);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />

<div class="date-wrapper">
  <div>
    <label for="date1">Date 1:</label>
    <input type="text" class="datepicker" id="date-1">
  </div>
  <div>
    <label for="date2">Date 2:</label>
    <input type="text" class="datepicker" id="date-2">
  </div>
  <div>
    <label for="date3">Date 3:</label>
    <input type="text" class="datepicker" id="date-3">
  </div>
  <div>
    <label for="date3">Date 4:</label>
    <input type="text" class="datepicker" id="date-4">
  </div>
  <div>
    <label for="date3">Date 5:</label>
    <input type="text" class="datepicker" id="date-5">
  </div>
</div>

Я считаю, что это соответствует вашим критериям:

  • Предыдущее поле даты должно быть меньше или «до» текущего поля даты.
  • Все предыдущие даты должны быть меньше этого поля даты.
  • Если дата изменяется, минимальная дата для следующих дат также должна быть обновлена.

Функция getDate() получает элемент и определяет, содержит ли он дату в формате String (на основе формата даты), и возвращает объект Date, равный этой дате или null.

Функция checkMinDate() - помочь нам определить даты ручного ввода. Проверяет введенную вручную дату по значению minDate. Если оно больше или равно minDate, оно вернет true. Если оно меньше minDate, возвращается false.

В нашем обратном вызове change мы используем .preventDefault(), чтобы остановить текущее действие. Это полезно для событий типа, где мы хотим проверить, что было введено. Позже мы можем вернуть true или false, чтобы позволить событию развиваться. Если checkMinDate не верно, мы можем очистить значение и вернуть false.

Надеюсь, это поможет!

...