Как разрешить ручной ввод даты для jQuery UI Datepicker?

#jquery #jquery-ui #jquery-ui-datepicker

#jquery #jquery-ui #jquery-ui-datepicker

Вопрос:

На моей странице есть jQuery UI datepicker, и должна быть возможность вводить даты вручную. Чтобы упростить задачу для пользователя, также должна быть возможность ввести краткую форму даты (только день и месяц), и она будет разрешена со следующей возможной датой, как только фокус будет смещен с поля.

Пример (немецкий формат даты):

29092019 должен быть разрешен до 29.09.2019

2909 должен быть разрешен до 29.09.2019

0103 следует перенести на 01.03.2020, когда 1 марта в этом году уже закончится.

Как мне начать с подобной проблемы?

 $( function() {
    $("#myDate").datepicker({
      dateFormat : "dd.mm.yy"
    });
});  
 <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>


<input type="text" id="myDate" />  

Комментарии:

1. «29042019 должен быть разрешен до 24.09.2019» это верно? Разве это не должно быть 24092019 -> 24.09.2019 ?

2. вы правы, это опечатка. Измените это сейчас!

3. Хорошо, благодаря предоставленным ответам мы довольно близки. Мне просто нужно выяснить, как я могу проверить проанализированные даты! В настоящее время можно получить значения, подобные, например, «40.15.2050» или «30.02.2019», чего не должно быть. Есть идеи?

4. Посмотрите, что происходит, когда вы запускаете это в консоли: new Date("30.02.2019") — оно возвращает Invalid Date — используйте это для проверки. Вы должны прочитать об объекте Date в JavaScript.

5. **** ЭТОТ ВОПРОС ЗАКРЫТ — БОЛЬШЕ ОТВЕТОВ НЕ ТРЕБУЕТСЯ! **** Вознаграждение получит @scott6 за его удивительную помощь в течение последних нескольких недель. Мне просто нужно подождать 24 часа, пока я не смогу его наградить…

Ответ №1:

Вот один из способов сделать это — комментарии ниже:

 // Some sample dates
let userDates = [
    "29092019",
    "2909",
    "0103",
    "1303",
    "1403"
];

// Run the sample dates through parseUserDate()
for (let userDate of userDates) {
    console.log(userDate   ":");
    console.log(parseUserDate(userDate));
}

function parseUserDate(dateStr) {
    let parsedDate;

    // If it's 8 characters long, slice into YYYY-MM-DD
    if (dateStr.length === 8) {
        let dateSplit = [
            dateStr.slice(4),
            dateStr.slice(2, 4),
            dateStr.slice(0, 2)
        ];

        parsedDate = new Date(dateSplit.join("-"));
    }

    // 4 characters long - slice into MM-DD and prefix with YYYY later.
    else if (dateStr.length === 4) {
        let monthDay = [
            dateStr.slice(2, 4),
            dateStr.slice(0, 2)
        ].join("-");

        // The current date - this is used to check if the user date should be next year.
        let now = new Date();

        // MM-DD with the current year.
        let userDateCurrentYear = new Date(now.getFullYear()   "-"   monthDay);

        // MM-DD with next year.
        let userDateNextYear = new Date((now.getFullYear()   1)   "-"   monthDay);

        // If the current date is past the MM-DD this year, set parsedDate to next year's date.
        if (now > userDateCurrentYear) {
            parsedDate = userDateNextYear;
        } else {
            parsedDate = userDateCurrentYear;
        }
    }

    return parsedDate;
}  

Комментарии:

1. Как я могу сохранить гибкость синтаксического анализатора для разных форматов дат?

2. @JonSnow Вы могли бы добавить дополнительный параметр к вызову функции: parseUserDate(dateStr, dateFormat) затем разделить dateStr соответствующим образом.

Ответ №2:

Попробуйте это..

для интеграции со средством выбора даты jQuery вы можете сделать это, как показано ниже

Правки:

  • добавьте неверную проверку даты и верните пустую строку для недопустимых дат
  • исправлена проверка даты: добавлена проверка високосного дня
  • исправьте переменную monDt (добавьте getMonth 1, поскольку месяц в JS начинается с 0)

 $(function(){
$('.datepicker').datepicker({
dateFormat:'dd.mm.yy'
});
$('.datepicker').on('blur',function(){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 amp;amp; 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 amp;amp; isValidDate(year,inputVal[1],inputVal[0]) amp;amp; inputVal[0] '.' inputVal[1] '.' year) || 
			   (inputVal.length==3 amp;amp; isValidDate('20' inputVal[2],inputVal[1],inputVal[0]) amp;amp; inputVal[0] '.' inputVal[1] '.20' inputVal[2]) || 
			   (inputVal.length==4 amp;amp; isValidDate(inputVal[2] inputVal[3],inputVal[1],inputVal[0]) amp;amp; inputVal[0] '.' inputVal[1] '.' inputVal[2] inputVal[3]) ||
			   ''; // set empty on invalid dates
    $(elm).val(result);
  } else $(elm).val('');   
}
</script>  
 <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>

<input type="text" id="myDate" class="datepicker" />  

И это пример для множественного выбора даты с некоторыми ограничениями. Вы можете приспособиться к тому, что вам нужно 🙂

amp; возвращает строку даты на основе формата datepicker

 $(function(){
	initDatePicker();
})

function initDatePicker(){
	// do a loop for custom property on each element
	$('.datepicker').each(function(){
        // you can find available formats here : http://api.jqueryui.com/datepicker/#utility-formatDate
		$(this).datepicker({
			dateFormat:'yy.mm.dd'
	    });
		// set minimum date from data attribute. 
		if (typeof $(this).data('mindate') != 'undefined') {
			$(this).datepicker('option','minDate',$(this).data('mindate'));
		}
		// set maximum date from data attribute. 
		if (typeof $(this).data('maxdate') != 'undefined') {
			$(this).datepicker('option','maxDate',$(this).data('maxdate'));
		}
		
		$(this).on('change',function(){
			parseInputDate(this);
			// now, set date relations :) 
			if (typeof $(this).data('nextelem') != 'undefined') {
				$($(this).data('nextelem')).datepicker( "option", "minDate", getDate( this ) );
			}
			if (typeof $(this).data('prevelem') != 'undefined') {
				$($(this).data('prevelem')).datepicker( "option", "maxDate", getDate( this ) );
			}
		});
		
	});
}

// get date function taken from : http://jqueryui.com/datepicker/#date-range
function getDate( element ) {
  var date;
  try {
	date = $.datepicker.parseDate( $(element).datepicker('option','dateFormat'), element.value );
  } catch( error ) {
	date = null;
  }
  return date;
}

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]
      format = $(elm).datepicker("option", "dateFormat"); // get current element's datepicker format
      
  // check if it's already a valid entry, then do nothing 
  if ($(elm).val() == $.datepicker.formatDate(format,$(elm).datepicker('getDate'))) return;    
  
  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;
  }	
  var getDateString = function(yyyy,mm,dd) {
	    var dt = new Date(yyyy,parseInt(mm,10)-1,dd);
	    // get datepicker format amp; get date string using datepicker's formatDate function
	    return $.datepicker.formatDate($(elm).datepicker("option", "dateFormat"),dt);
  }
	
  if (inputVal!=null amp;amp; 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, amp; generate date string according to datepicker format 
  var result = (inputVal.length==2 amp;amp; isValidDate(year,inputVal[1],inputVal[0]) amp;amp; getDateString(year,inputVal[1],inputVal[0])) || 
				   (inputVal.length==3 amp;amp; isValidDate('20' inputVal[2],inputVal[1],inputVal[0]) amp;amp; getDateString('20' inputVal[2],inputVal[1],inputVal[0])) || 
				   (inputVal.length==4 amp;amp; isValidDate(inputVal[2] inputVal[3],inputVal[1],inputVal[0]) amp;amp; getDateString(inputVal[2] inputVal[3],inputVal[1],inputVal[0])) ||
				   ''; // set empty on invalid dates
      $(elm).val(result);
  } else $(elm).val('');  

  // add validation to invalidate out-of-range value
  // get selected/entered date
  var cdate = $(elm).datepicker('getDate');
  // get range
  var minDateAttr = $(elm).datepicker("option", "minDate");
  var maxDateAttr = $(elm).datepicker("option", "maxDate");
  // get datepicker instance
  var inst = $('#myDate').data("datepicker");
  var isValid = false;
  if (minDateAttr!=null) {
	// get range as date object
	var minDateObj = $.datepicker._determineDate(inst, minDateAttr, new Date());
	if (minDateObj<=cdate) isValid = true
  }
  if (isValid amp;amp; maxDateAttr!=null) {
	// get range as date object
	var maxDateObj = $.datepicker._determineDate(inst, maxDateAttr, new Date());
	if (maxDateObj>=cdate) isValid = true
  }
  if (!isValid) $(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 rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">


Dates : 
<input type="text" id="myDate" class="datepicker" data-nextelem="#myDate2"  data-mindate="-20" maxlength="10" style="width:80px" /> -
<input type="text" id="myDate2" class="datepicker" data-prevelem="#myDate" data-nextelem="#myDate3"  maxlength="10" style="width:80px"/> -
<input type="text" id="myDate3" class="datepicker" data-prevelem="#myDate2"  data-maxdate=" 2y" maxlength="10" style="width:80px"/>  

Комментарии:

1. Этот пример работает замечательно и почти так, как описано. Не хватает только одной маленькой вещи: поле ввода также должно работать со стандартным jQuery UI datepicker. Должна быть возможность использовать средство выбора или прямой ввод. Когда я добавляю вашу функцию в свое текущее текстовое поле, она работает только для datepicker, но НЕ для прямого ввода. Я тестировал с помощью селектора «.datepicker», а также с помощью «.hasDatepicker». Первый класс — это класс, который jQuery datepicker использует для создания средства выбора вообще, второй класс — сгенерированный.

2. ПОЧТИ ХОРОШО!! Мне просто нужно выяснить, как я могу проверить проанализированные даты! В настоящее время можно получить значения, подобные, например, «40.15.2050» или «30.02.2019», чего не должно быть.

3. @SchweizerSchoggi проблем возникнуть не должно. Пожалуйста, посмотрите мой обновленный ответ 🙂

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

5. @SchweizerSchoggi : oops.. извините за это, getMonth должен быть добавлен к 1 .. ответ обновлен 🙂