You are viewing limited content. For full access, please sign in.

Question

Question

How to restrict a date picker to only queried dates

asked on March 22, 2021 Show version history

I know there are some similar questions out there, but I haven't figured out an answer to this one.  We have a Form that relies on a set of user-specified time/date slots that come from the end user.  The dates may be added to, or taken away from, as needed.

 

What I need, and haven't figured out yet, is a script that will allow me to have a date picker that only shows dates as "available" if that date was returned from my database query.  All other dates would be greyed out / unavailable.  Does anyone know how I could do that?

 

The inverse operation is described in this post, but I haven't been able to get it flipped around.

0 0

Answer

SELECTED ANSWER
replied on March 22, 2021 Show version history

I haven't tested it - but the script I posted on the other post - line 31 looks like this: 

return (t!=6 && t!=0 && blackoutDatesList.indexOf(string) == -1);

 

That is saying date is not Saturday -and- date is not Sunday -and- date is not on the list of blackout dates.  It would probably work to change the last bit to say it must be in the list of dates.  Like this: 

return (t!=6 && t!=0 && blackoutDatesList.indexOf(string) >= 0);

 

It'll probably work with all the other code and instructions in place on that post.

Also - please consider editing this post to make it a Question instead of a Discussion - so that you have the ability to mark it as answered once complete.

0 0
replied on March 23, 2021 Show version history

Finally got this to work, and work it did!  Thanks Matthew!

On a related note, to anyone else looking at this; it's very important that you ONLY change the date format in the indicated line of code; all other date formats are required for the date picker to recognize them as valid.  I hadn't even realized I'd left an incorrectly formatted date in one spot, and it took me ages to realize my mistake.

1 0
replied on March 23, 2021

Correction - it almost works.  This line:

return isValidDate(moment(value, "yyyy-mm-dd").toDate());

always returns "false " ('not a valid date' message) no matter what format I choose on the date date picker or put in this string.  Not sure how to fix it at this point.

0 0
replied on March 23, 2021

I may just be sleep deprived (it's 4 AM and I've been up for hours with a cranky toddler) - but shouldn't that be uppercase there?

YYYY-MM-DD not yyyy-mm-dd ?

0 0
replied on March 23, 2021

Thanks again Matthew.  I was sleep-deprived and cranky myself last night by that point.  All I had to do (grumble) was change the 'dd' to 'DD' like this (for the associated format):

return isValidDate(moment(value, "MM/DD/yyyy").toDate())

 

1 0
replied on March 23, 2021

Fantastic!  I'm very glad to hear you got it working.

0 0
replied on March 3, 2023

Thank you for explaining what this extremely important line meant. I wanted to use mine to restrict to only Sundays and was able to easily replicate what you did using your clarification.

0 0

Replies

replied on January 13, 2023 Show version history

Hi,  I tried using the original list (with blackout dates) and reversed it to only show dates on a list (for employee onboarding this is a list of available orientation dates).  Nothing I tried worked... have manipulated formats (mm-dd-yy vs yy-mm-dd) to no avail.  Any suggestions?

And... the selected dates are actually blacked out but the day after them is available on the calendar.  I had to subtract one day from each target date in my list for it to work - but this is not intuitive and it would be nice if the dates just worked as entered/intended.

I'm no JS expert, but I'm pretty savvy.  This is proving to be a nightmare - I've found all 21 examples of date manipulation in these forums but nothing provides a simple solution for the simple task of providing "available" dates in the calendar based upon a list of dates :(

//create the array of blackout dates
var orientationDatesList = new Array();

//this function is run when the form is loaded
$(document).ready(function(){

  //set the date range of the Date field between tomorrow and 365 days in the future
  var today = new Date();
  var startDate = new Date();
  startDate.setDate(today.getDate() + 1);
//startDate.setDate(today.getDate());  
  var endDate = new Date();
  endDate.setDate(today.getDate() + 365);
  var minDate = $.datepicker.formatDate('yy-mm-dd', new Date(startDate));
  var maxDate = $.datepicker.formatDate('yy-mm-dd', new Date(endDate));
  $('.myLimitedDate input').attr('min',minDate);
  $('.myLimitedDate input').attr('max',maxDate);

  //loop through each date in the blackout date list, and add it to an array
  orientationDatesList.length = 0;
  $('.orientationDates option').each(function() {
    orientationDatesList.push(formatDate(new Date($(this).val())));
  });
  
  //the following four function work together to disable any dates on the picker 
  //that are weekends or are on the orientationDatesList array
  //they also add a validation (parsley) setting for invalid date entries
  function isValidDate(n) {
    var t = n.getDay();
    var d = n.getDate();
//    var string = jQuery.datepicker.formatDate('mm-dd-yy', n); //does not work
    var string = jQuery.datepicker.formatDate('yy-mm-dd', n);  //original
//  return (t!=6 && t!=0 && orientationDatesList.indexOf(string) == -1); //exclude these dates (day +1)
//  return (t!=6 && t!=0 && orientationDatesList.indexOf(string) == 1); //exclude these dates (does not work)
//  return (t!=6 && t!=0); //exclude just weekends  (this works!)
    //for the code below to work, the dates in the date list must all be 1 day less than the desired date (!)
    return (t!=6 && t!=0 && orientationDatesList.indexOf(string,0) >= 0);  //include ONLY these dates
  }
  function checkDate(n) {
    return[isValidDate(n),""];
  }
  function checkField(input, inst) {
    if ($(input).closest('li').hasClass('myLimitedDate')) {
      $(input).datepicker("option", {beforeShowDay: checkDate});
    }
  }
  $.datepicker.setDefaults( {beforeShow: checkField} );
  window.Parsley.addValidator('limiteddate', {
    validateString: function(value) {
      //IMPORTANT! this date format needs to match the format you set for the field on the layout page
//    return isValidDate(moment(value, "YYYY-MM-DD").toDate()); 
      return isValidDate(moment(value, "MM-DD-YYYY").toDate()); 
    },
    messages: {
      en: 'Not an available date.' 
    }
  });
  $('.myLimitedDate input').attr('data-parsley-limiteddate','');
});

//this function is run when the lookups are completed.
$(document).on("onloadlookupfinished", function () {
  //loop through each date in the blackout date list, and add it to an array
  orientationDatesList.length = 0;
  $('.orientationDates option').each(function() {
    orientationDatesList.push(formatDate(new Date($(this).val())));
  });
});

//function to return any date formatted as yyyy-mm-dd
function formatDate(date) {
  var d = new Date(date),
    month = '' + (d.getMonth() + 1),
    day = '' + (d.getDate() +1),
    year = d.getFullYear();
  if (month.length < 2) 
    month = '0' + month;
  if (day.length < 2) 
    day = '0' + day;
  return [year, month, day].join('-');
//return [month, day, year].join('-');  //this causes calendar to be unavilable
}
1 0
replied on January 18, 2023

Hi John,

 

Nightmare.  Yes, that sums up trying to black out / activate only certain dates using a Forms datepicker nicely.

We have spent countless hours banging our heads against this particular wall, as well as utilizing the services of someone who DOES know javascript quite well.  Ultimately, we ended up just creating a custom date field out of a single-line field and storing code for it on the server.

You might have a little bit better luck with your approach, using a small-ish subset of days that ARE available and disabling everything else.  One important thing to know about working with these date pickers is they tend to get reset every time you turn you back (and random times when you did nothing at all).  To combat that, you have to constantly be re-establishing your valid dates.

Based on some of my earlier work and your scenario, I put together the code snippet below.  It more or less works; you can be the judge.  The main things to note about this include:

  • I created a lookup rule to store the data in a dropdown that I call "Available Dates" - you'll see that field referenced in the code below.
  • The ugly setTimeout function - For some reason I COULD NOT get the 'lookupcomplete' event listener to trigger for the starting load on this simple Form, so I just wait a bit then go.  It's important for you to know, however, that even if I did trigger this off the lookup event, I would still have added a setTimeout.  They're ugly, and I hate to use them, but I have seen too many times where the listener event triggered before the data finished loading / populating.
  • There is no parsley validation.  I've had issues with trying to add validation like that, so I bypassed it by making the field required and clearing the value if an invalid date is entered.  Feel free to do it a different way.

 

Without further ado, here's another long code snippet that may or may not be helpful to you:
 

// set available dates in the datepicker of the field passed as a parameter
function setAvailableDates($field, availableDates){
  //set variables
  var today = new Date();
  today.setHours(0,0,0,0); // sets date to midnight so it will properly evaluate
  var oneYear = new Date();
  oneYear.setFullYear(oneYear.getFullYear() + 1);
  
  // set the min and max attributes on the date field
  $field.attr('min',today.toISOString().split('T')[0]);
  $field.attr('max',oneYear.toISOString().split('T')[0]);

  // Set beforeShowDay option to grey out unavailable dates
  $field.datepicker('option','beforeShowDay', function(date) {
    // if date < today or not in the list of available dates
    if (date < today || availableDates.indexOf(date.toLocaleDateString()) < 0){
      return [false, "date unavailable", ''];
    }
    else if (availableDates.indexOf(date.toLocaleDateString()) >= 0){
      return [true, '', ''];
    }
  });
};


// Verifies that entered date value is on our list. 
// Takes Date field and available dates array as parameters.
function isValidDate($field, availableDates){
  var selectedDate = $field.val();
  //debugger;
  if (availableDates.indexOf(selectedDate) == -1){
    // clear field value
    $field.val('');
    // call function to disable unavailable dates
    setAvailableDates($field, availableDates);
    // inform user that they need to use a new date
    alert ("Date Unavailable - Unavailable Dates are Greyed Out.\nPlease Choose a New Date");
  };
};

// Main functions
$(document).ready(function(){
  var $dateField = $('li[attr="Limited_Date"] input');
  var availableDates = [];
  
  // pause for a moment (this is ugly, but I've seen many times where this
  // function runs before the field has finished populating
  setTimeout(function(){
    // add available dates from lookup into array
    $('li[attr="Available_Dates"] select option').each(function(){
      if($(this).val() != ''){
        availableDates.push($(this).text());
        // call function to disable unavailable dates
    	setAvailableDates($dateField, availableDates);
      }
    });
    // call function to disable unavailable dates
    setAvailableDates($dateField, availableDates);
  },400);
  
  // reset the beforeShowDate every time the user clicks on the date field
  $dateField.on('click', function(){
    // call function to disable unavailable dates
    setAvailableDates($dateField, availableDates);
  });
  
  // When a date is entered / selected,
  $dateField.on('change', function(){
    // verify that the entered value is a good one
    isValidDate($dateField, availableDates);
  });
  
});

 

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.