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

Question

Question

Default Date Calculation and data validation

asked on January 28, 2020

I have a date field on a form that I would like to default to today's date plus 3 business days.  I also want to ensure that the user can not select a date that is earlier than the calculated default date.  I'm new to this type of behavior, so I'm not sure if this would be javascript, a formula, an Error Message rule, or some combination of the above.  Any help would be appreciated.

 

Thanks.

 

0 0

Answer

SELECTED ANSWER
replied on January 28, 2020

Get ready, this one took me a minute, but it completely possible with the moment.js that's built into Laserfiche Forms. So I'll give you the code first then explain each part.

//Sets date to two business days from current date
  var twoBusinessDays = addWeekdays(currentDate, 2).format('YYYY-MM-DD');
  var sameDay = addWeekdays(currentDate, 0).format('YYYY-MM-DD');
  
  function addWeekdays(date, days) {
    date = moment(date);
    while (days > 0) {
      date = date.add(1, 'days');
      //Decrease "days" only if it's a weekday.
      if (date.isoWeekday() !== 6 && date.isoWeekday() !== 7) {
        days -= 1;
      }
    }
    return date;
  }
  
  //Sets Minimum Dates for datepicker
  $('#Field70').on('click', function(){
    if (($('#Field70-0').prop('checked') == true) || ($('#Field70-1').prop('checked') == true) || ($('#Field70-2').prop('checked') == true) || ($('#Field70-3').prop('checked') == true)){
      
      $("#Field18").prop('min', twoBusinessDays);
      $("#Field18").val(moment(twoBusinessDays).format('MM/DD/YYYY'));

    }
    else{

      $('#Field18').prop('min', currentDateFormatted);
      $('#Field18').val(moment(currentDateFormatted).format('MM/DD/YYYY'));

    }
    
   });

Ok. So if your not familiar with JavaScript the // and text is a comment. It doesn't do anything but inform you.

We'll break it into two pieces since it technically is.

//Sets date to two business days from current date
  var twoBusinessDays = addWeekdays(currentDate, 2).format('YYYY-MM-DD');
  var sameDay = addWeekdays(currentDate, 0).format('YYYY-MM-DD');
  
  function addWeekdays(date, days) {
    date = moment(date);
    while (days > 0) {
      date = date.add(1, 'days');
      //Decrease "days" only if it's a weekday.
      if (date.isoWeekday() !== 6 && date.isoWeekday() !== 7) {
        days -= 1;
      }
    }
    return date;
  }

Ok, so the var portion is setting a variable to get the date from today + 2 (twoBusinessDays) and the current date.

The function takes the date (today) and the days (Two business and 1 business days) and uses them as "reference points". I'll try to keep the jargon to a minimum also to make my points. The if portion of it checks if today is a weekend (Saturday or Sunday) and then adds the days from there. It makes sure it only adds business days, not calendar days.

The twoBusinessDays variable (var) is where you will change it. Make it something like threeBusinessDays and change the 2 inside the parentheses on the same line to a 3. That should be all it will take to make this work if you know how to set up the rest.

 

The next part is where the magic actually happens. That first part just sets up needed background "magic".

 //Sets Minimum Dates for datepicker
  $('#Field70').on('click', function(){
    if (($('#Field70-0').prop('checked') == true) || ($('#Field70-1').prop('checked') == true) || ($('#Field70-2').prop('checked') == true) || ($('#Field70-3').prop('checked') == true)){
      
      $("#Field18").prop('min', twoBusinessDays);
      $("#Field18").val(moment(twoBusinessDays).format('MM/DD/YYYY'));

    }
    else{

      $('#Field18').prop('min', currentDateFormatted);
      $('#Field18').val(moment(currentDateFormatted).format('MM/DD/YYYY'));

    }
    
   });

The first part is kind of set to my case, but can easily be changed and I'll tell you how in a bit. It says that when a field I choose (Field70 in this case) is clicked, to run the rest of the code.

From there the if statement checks which radio button (from the field I choose) is selected and reacts accordingly. If the specific radio buttons I choose are selected (checked is the JavaScript terminology) then run the little bit of code in the first "{" brackets.

That code sets the "min" value of the date field (which is how you get the jump in time) and then formats it in a way that won't mess with the Laserfiche built-in code. The "min" property (using .prop()) is what you want to set to get the calendar to not allow the selection of days before the date you set.

If the radio buttons aren't "checked" then it will set the calendar to be the same business day as today (mind you it's business days, so if it's Saturday or Sunday it will be Monday. 

 

It seems like you want only business days which leads me to believe you also don't want them to choose weekends. If you don't have a solution I have one in place with all this code as well that you can have. I'll post it below.

//Remove weekends from selectable options
  
    function isCorrectDate(n) {
    var t = n.getDay();
    return (t!=6 && t!=0);
  }
  function checkDate(n) {
    return[isCorrectDate(n),""];
  }
  function checkField(input, inst) {
    if ($(input).closest('li').hasClass('myDate')) {
      $(input).datepicker("option", {beforeShowDay: checkDate});
    }
  }
  $.datepicker.setDefaults( {beforeShow: checkField} );
  window.Parsley.addValidator('noweekend', {
    validateString: function(value) {
      return isCorrectDate(new Date(value));
    },
    messages: {
      en: 'Not valid date.'
    }
  });

  $('.myDate input').attr('data-parsley-noweekend','');

I can't take credit for this one. I actually got it off the answers board here but modified it a tiny bit to fit my form. It works great though and works with my code above. Please let me know if I could better elaborate on any of what I said or if you're unsure where to put in your values (Field# here, q# there, etc.)

 

Hopefully this answers your question as you asked it. If not let me know.

1 0
replied on January 28, 2020

Tanner,

That looks like it should work with some tweaking.  I do think I want the functionality of limiting the selections on the calendar to weekdays.  I don't think I need the functionality of having the code triggered by clicking in another field.  The date field should just default to three workdays after today's date when the form opens, and fire again to check the selected date when the user changes the default value.  I'm not sure what to use as field names though; my fields don't have names like #Field70.  Where would I find the field name; is it the same thing as the variable name?

1 0
replied on January 29, 2020

Hey Mike,

  So generally speaking your inputs in a form are the #Field numbers.

If you look at the picture above when you're in the CSS/JavaScript portion of the form itself you get the id number of the entire field. The #Field(number) is usually the #q(number). When using radio buttons however you add a -(0- whatever number) to the end of the #Field(number) label. For instance, the radio buttons on that picture would be #Field3-0 and #Field3-1, #Field73-0 and #Field73-1, and #Field69-0 and #Field69-1 if I wanted to target the radio buttons themselves.

 

The #Field(number) can also be found on the developer tools of your browser. If you right-click on the input itself (not the text or blank space) and hit the "Inspect Element" option it will bring up your developer tools and show you in the HTML what the #Field(number) is for that input. Here's a picture example.

I'm using Google Chrome, so that's what my developer tools look like, but the code will look the same. The bottom arrow is the input field I'm "inspecting" the Top arrow is where you can find the #Field(number) ID of the input field.

Kind of a long-winded explanation, but hopefully it helped out. Just let me know if you have any more questions.

1 0
replied on January 29, 2020 Show version history

I stripped out the test for having a radio button control checked, and updated it for three business days.  I tried it out and it doesn't seem to trigger; nothing happens in the date field to indicate that the first date I can select would be three business days from now, and nothing happens when I select today's date, tomorrow's date, etc. 

Also, I'd like to use the code you provided above to remove Weekends from the selections on the calendar, but I don't know how to call that function or have that function reference my date field. 

 

//Sets date to three business days from current date
  var threeBusinessDays = addWeekdays(currentDate, 3).format('YYYY-MM-DD');
  var sameDay = addWeekdays(currentDate, 0).format('YYYY-MM-DD');
  
  function addWeekdays(date, days) {
    date = moment(date);
    while (days > 0) {
      date = date.add(1, 'days');
      //Decrease "days" only if it's a weekday.
      if (date.isoWeekday() !== 6 && date.isoWeekday() !== 7) {
        days -= 1;
      }
    }
    return date;
  }
  
  //Sets Minimum Dates for datepicker
  $('#q15').on('click', function(){
    
      
      $("#q15").prop('min', threeBusinessDays);
      $("#q15").val(moment(threeBusinessDays).format('MM/DD/YYYY'));

    
   });

1 0
replied on January 29, 2020

That's on me. I forgot I have 2 global variables I didn't include. Add these two variables to your code. Preferably at the top. I can't believe I missed them. Sorry about that.

 

var currentDate = moment();
var currentDateFormatted = currentDate.format('YYYY-MM-DD')

Also, change the 2nd and 3rd #q15 to #Field15. You want to target only the Field itself. The #q15 will target the entire DIV, which includes the white space around your date picker and the label. Otherwise, that should work.

 

As for the Weekends removal. On the same spot in your picture if you click "Advanced" and add the class myDate. Then simply paste the code I gave you in to your JavaScript you won't have to call the function at all. It will automatically remove them for you with any date field that has the class myDate. Again, let me know of any more issues that arise.

1 0
replied on January 29, 2020 Show version history

Ok, I've added myDate to the CSS Class section on the Advanced tab for the date control.  My code in the JavaScript box for the form now looks like this:

 

var currentDate = moment();
var currentDateFormatted = currentDate.format('YYYY-MM-DD')

//Remove weekends from selectable options
  
    function isCorrectDate(n) {
    var t = n.getDay();
    return (t!=6 && t!=0);
  }
  function checkDate(n) {
    return[isCorrectDate(n),""];
  }
  function checkField(input, inst) {
    if ($(input).closest('li').hasClass('myDate')) {
      $(input).datepicker("option", {beforeShowDay: checkDate});
    }
  }
  $.datepicker.setDefaults( {beforeShow: checkField} );
  window.Parsley.addValidator('noweekend', {
    validateString: function(value) {
      return isCorrectDate(new Date(value));
    },
    messages: {
      en: 'Not valid date.'
    }
  });

  $('.myDate input').attr('data-parsley-noweekend','');

//Sets date to three business days from current date
  var threeBusinessDays = addWeekdays(currentDate, 3).format('YYYY-MM-DD');
  var sameDay = addWeekdays(currentDate, 0).format('YYYY-MM-DD');
  
  function addWeekdays(date, days) {
    date = moment(date);
    while (days > 0) {
      date = date.add(1, 'days');
      //Decrease "days" only if it's a weekday.
      if (date.isoWeekday() !== 6 && date.isoWeekday() !== 7) {
        days -= 1;
      }
    }
    return date;
  }
  
  //Sets Minimum Dates for datepicker
  $('#q15').on('click', function(){
    
      
      $("#Field15").prop('min', threeBusinessDays);
      $("#Field15").val(moment(threeBusinessDays).format('MM/DD/YYYY'));

    
   });

I tried testing in Preview mode of the form, and it still does not appear to be doing anything.  Is there something else that might have been missed?  

Edit:  It does appear that the weekends are being disabled, so that part does work. Also, the code does not seem to trigger in Preview mode, only when the form is opened from the Process Diagram or from the published URL.

Edit2:  Correction, it does fire in Preview mode if I click Preview while in the CSS and JavaScript tab, and then if I go back to the Layout tab it works too.  Guess it just took switching back and forth between tabs to get it to refresh and recognize the code.  However it still is just the weekend code that seems to be doing anything.

 

 

 

1 0
replied on January 29, 2020

I'm going to do some debugging with you. Can you try changing $("#q15").on('click') to $(document).on('click')? That will tell it to execute the code if you click anywhere on the form. So if that works, it's a problem with the selector or the $() part of it.

0 0
replied on January 29, 2020

That worked.  For some reason it didn't like the field/control reference and the document click event fired the code successfully.

 

Thanks!

1 0
replied on January 29, 2020

Your welcome. if clicking on the document itself doesn't seem to get the job done in a way that satisfies you, just try messing with different parts of the form in place of the $(document). I've used fields, radio buttons, checkboxes, you name it. I'm glad we got it working though!

1 0
replied on January 29, 2020

I actually changed the document on click to document.ready and that works great.  Thanks again.

1 0

Replies

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

Sign in to reply to this post.