How can I dynamically recreate / change Vanilla JS Datepicker element option(s)? - javascript

I am using a Vanilla JS Datepicker on a page that has a dropdown for multiple store locations, each of which have varying days of operation. Some being closed weekends, others being open weekends, some being closed Sunday, open Saturday, etc.
My objective is to create a single datepicker using an event listener on a selecte element with options for various locations.
In the event listener, I wish to call a function that will create the datepicker with the options for the days to be closed for that given location.
What I am experiencing is when the first location is selected, the datepicker populates according to that locations days of operation. Subsequent changes to the select though does not change the calender from original location. I am passing an array to the function that creates the datepicker.
I verified the array passed to the datepicker function changes with each option change, but it is not reflected on the calender.
let date1 = document.querySelector('input[name="Service_Date"]');
let closeDays = [];
function d1(days){
let serviceDate = new Datepicker(date1, {
autohide:true,
nextArrow:"<span class='fa fa-chevron-right'></span>",
prevArrow:"<span class='fa fa-chevron-left'></span>",
minDate:"today",
daysOfWeekDisabled:days
});
}
closeDays = [0];
d1(closeDays);
closeDays = [];
closeDays = [0,6]
d1(closeDays);
The above code will generate an initial datepicker with Sundays (0) disabled after the 1st function call, but after the 2nd call, the disabled days should be Sunday and Saturday, but they are not.
I tried various attempts at calling the function, consoling out the array and the function parameter. They both change, but not the calendar.

let date1 = document.querySelector('input[name="Service_Date"]');
let closeDays = [];
let serviceDate = '';
function d1(days){
if(serviceDate != ''){
serviceDate.destroy();
}
serviceDate = new Datepicker(date1, {
autohide:true,
nextArrow:"<span class='fa fa-chevron-right'></span>",
prevArrow:"<span class='fa fa-chevron-left'></span>",
minDate:"today",
daysOfWeekDisabled:days
});
}
closeDays = [0];
d1(closeDays);
closeDays = [];
closeDays = [0,6]
d1(closeDays);

Related

I want to create a script for google sheets that will make multiple copies of a sheet and place the new sheets to the left of the active sheet

I am very new to using google scripts. I have a spreadsheet with tabs that are titled by date. I found the following script that will enable me to create a variable number of duplicate sheets. The script will also automatically rename the new sheets by changing the date to the next date. The only problem is that all of the new sheets are added to the far right of the document. I want each copy to be placed to the left of the active sheet. So if I have a tab titled 1/3/21 and I make 3 copies of that tab, the new tabs will read from left to right 1/6/21; 1/5/21; 1/4/21. This is the script I am using. I had to disable "Enable Chrome V8 runtime" for this script to work.
function duplicatesheet() {
var as = SpreadsheetApp.getActiveSpreadsheet(); // active spreadsheet
var s = as.getActiveSheet(); // first sheet object
var dateCell = "A6:N6"; // cell containing first date
var N = 5; // number of copies to make
var startDate = new Date(s.getRange(dateCell).getValue()); // get the date stored in dateCell
var day = startDate.getDate(); // extract the day
var month = startDate.getMonth(); // extract the month
var year = startDate.getFullYear(); // extract the year
// loop over N times
for (var i = 0; i < N; i++) {
var asn = s.copyTo(as); // make a duplicate of the first sheet
var thisSheetDate = new Date(year, month, day+(i+1)); // store the new date as a variable temporarily
asn.getRange(dateCell).setValue(thisSheetDate); // writes the date in cell "B3"
asn.setName(Utilities.formatDate(thisSheetDate, undefined, "MM/dd/yy")); // sets the name of the new sheet
}
}
Explanation:
As the other answer explained you can use insertSheet(sheetName, sheetIndex, options). This answer explains how you can incorporate that function into your code but also how to make your code faster and more efficient.
In your code dateCell is a range of cells "A6:N6", but you only need a single value and that is A6. Therefore simply, change it to A6.
You don't need to create a date object of your value. If A6 in your sheet contains a date value, then GAS will pick it up correctly.
You don't need to build your own date objects iteratively. You can use:
startDate.setDate(startDate.getDate()+1);
and that will increase the date by one day. In this way you can get rid of day, month and year variables.
I am not sure why you put undefined as the second argument of Utilities.formatDate and also not sure why your script editor didn't drop an error. But you probably wanted to use as.getSpreadsheetTimeZone() instead.
To correctly insert the sheets to the left of the active sheet inside the for loop you need an index expression like that sindex-N+1. The +1 is used because getIndex starts counting from 1. Namely for the first sheet in your document getIndex would return 1. But the sheetIndex parameter in insertSheet accepts an index that starts from 0.
Solution:
function duplicatesheet() {
var as = SpreadsheetApp.getActiveSpreadsheet();
var s = as.getActiveSheet();
var sindex = s.getIndex();
var dateCell = "A6";
var N = 2;
var startDate = s.getRange(dateCell).getValue();
// loop over N times
for (var i = 0; i < N; i++) {
startDate.setDate(startDate.getDate()+1);
var startDateStr = Utilities.formatDate(startDate, as.getSpreadsheetTimeZone(), "MM/dd/yy")
var asn=as.insertSheet(startDateStr, sindex-N+1, {template: s});
asn.getRange(dateCell).setValue(startDate);
}
}
This seems kind of easy to do:
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = SpreadsheetApp.getActiveSheet();
let index = sheet.getIndex();
ss.insertSheet("New Sheet", index - 1, {template: sheet, });
}
After executing this code your sheet should look like this after being executed:
Reference
Selection of sheet in Apps Script
insertSheet(sheetName, sheetIndex, options)

Question About the App Script of Dynamic Dropdown list with Section Navigation in Google Form

I am trying to make a dynamic dropdown list and Section Navigation in Google Form. However, my script can auto delete the choice when the quota has been met, the choice can’t navigate to the related page for other selections.
I am planning a health check event for my hospital. It needs to reserve by timeslot and date due to the crow control policy. The links below are my Google Spreadsheet for the form and my daft Google Form of the function.
https://forms.gle/ZV9Djni8hyQGdAd86
https://docs.google.com/spreadsheets/d/1F1dpGCTSlpEOUMh5txsZouhx784JmJvh66IsiGfDTtg/edit?usp=sharing
Reference:
How to set the go to sections on a Google Forms question using app script
https://www.pbainbridge.co.uk/2019/04/dynamically-remove-google-form-options.html
function appointmentSlots() {
var form = FormApp.openById("1VqFBKBD_-iKYk_3Ze40j2tvRIi093-alaoCDsXpFi8k");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var date1timelist = form.getItemById("2101588132").asListItem();
var optionsSheet = ss.getSheetByName('Date Options');
var dateoptions = optionsSheet.getRange('A2:A3').getValues();
var dateleft = optionsSheet.getRange('C2:C3').getValues();
var day1sheet = ss.getSheetByName('9/3');
var day1timeoptions = day1sheet.getRange('A2:A4').getValues();
var day1left = day1sheet.getRange('C2:C4').getValues();
var formFieldsArray = [
["9/3", 2061926149],
["10/3", 1632977105]
];
for(var h = 2; h < formFieldsArray.length; h++) {
var datelist = form.getItemById(formFieldsArray[h][2]).asListItem();
var avaibledateoptions = [];
var sectionday1timeslots = form.getItemById("2101588132").asPageBreakItem();
var sectionday2timeslots = form.getItemById("1630116063").asPageBreakItem();
var datechoice = datelist.getChoices();
var optionsDataLength = dateoptions.length;
for (var i=0; i<optionsDataLength; i++) {
var choice = dateoptions[i][0];
var left = dateleft[i][0];
if ((choice != '') && (left > 0) == formFieldsArray[h][2]) {
if (formFieldsArray[h]= "9/3") {
datechoice.push(datelist.createChoice(avaibledateoptions,sectionday1timeslots));
}
else {
datechoice.push(datelist.createChoice(avaibledateoptions,sectionday2timeslots));
datelist.setChoices(avaibledateoptions);
}
}
}
}
var day1avaibledateoptions = [];
var optionsday1Length = day1timeoptions.length;
for (var i=0; i<optionsday1Length; i++) {
var day1timechoice = day1timeoptions[i][0];
var day1timeleft = day1left[i][0];
if ((day1timechoice != '') && (day1timeleft > 0)) {
day1avaibledateoptions.push(day1timechoice);
}
}
date1timelist.setChoiceValues(day1avaibledateoptions)
}
//etc for day2 timeslots choice and day3 timeslots
}
}
}
In order to modify your form depending on the changing cell values in your Spreadsheet (caused by new form submissions) you will need to set up an installable onChange trigger that will basically run your function when a change on your Spreadsheet is done (like one coming from a form submission). To create such a trigger, please access your trigger pannel and then click on Create trigger and select as the event type onChange assigning it to the function you will be using to create/delete the form items.
Once a user submits a new form and you do certain calculations on your Spreadsheet to determine how many slots are free for that time slot, you can take the value of the cell that tells you how many free appointments are free for that time and if that number is 0 you can proceed to delete that question element using the method deleteItem().
If you eventually end up resetting the form (because your time slot is free again or someone cancels the meeting), you can undo this by creating back the element.
The following piece of code is a basic example on how to delete and create form items based on the changes of a Spreadsheet cell. It has self explanatory comments:
function onChange() {
// Get the different sheets where you have all your left places in your time slots
var sheet = SpreadsheetApp.getActive().getSheetByName('A');
// Get your form
var form = FormApp.openById('FORMID');
// Here you would get each element that might depend on whether there are any
// appointments left or not
var element = form.getItems()[2];
// Get the cell value that tells you if the time slot is already full (full=0)
var value = sheet.getRange('C2').getValue();
// If the value is 0 it means that this time slot is all completed and nobody
// should be able to select it again
if (value == 0) {
// delete this item
form.deleteItem(element);
// if it is not full yet, it might be because your reset the time slot and therefore
// the element does not exist any more
} else {
// if the element exists dont do anything but if it doesnt and there are available
// apointments create it again
if (!element) {
form.addMultipleChoiceItem().setTitle('B').setChoiceValues(['Cats', 'Dogs']);
}
}
}
If you want to remove a choice option rather than an Item, you can look for the item, get all the choices as an array and then remove the choice you don't want any more from this array. Finally, you can update the item with your updated options with setChoices(). Here is a code example on how to achieve this:
function myFunction() {
// This is an example where I only have a single multiple choice item
var choiceItem = FormApp.getActiveForm().getItems(FormApp.ItemType.MULTIPLE_CHOICE)[0].asMultipleChoiceItem();
// Get current choices array
var choices = choiceItem.getChoices();
// Get choice you want to delete, this would be your times or dates obtained from
// the cell values
var choiceToBeRemoved = "A";
// remove choice from array
choices = choices.filter(function(choice){return choice.getValue() !== choiceToBeRemoved});
// Set updated choices
choiceItem.setChoices(choices);
}
References
setChoices
Javascript filter()

How can I get dynamic Timepicker values in javascript

So, I'm using Kendo UI MVC where I want to create a type of request. However, the number of user controls is dynamic and depends of how many requests of that type the user wants to make. So to create them, I have this:
#while(number!=numberAdds){
<br />
<label style="margin-right:1em;margin-top:1.5em">Start time:</label>
#(Html.Kendo().TimePicker()
.Name("startTime"+(number+1))
.Min("8:00")
.Max("19:50")
.Interval(10)
)
<label style="margin-left:2.5em; margin-right:1em">End time:</label>
#(Html.Kendo().TimePicker()
.Name("endTime"+(number+1))
.Min("8:10")
.Max("20:00")
.Interval(10))
number++;}
And it works. Now, when I click the submit button, what I'm trying to do is to create an array of StartTimes and EndTimes so I can send it via Ajax Post to the controller. However, I'm not able to do so, because of the TimePickers ID. I'm trying to do something like this:
$(document).on("click", "#confirm-request", function (e) {
var date = $("#date").data("kendoDatePicker").value();
var stringDate = kendo.toString(date, "yyyy-MM-dd");
var number = 0;
var numberAdds = parseInt(document.getElementById("number-adds").textContent);
var timeStartStrings = new Array();
var timeEndStrings = new Array();
for (number; number < numberAdds; i++) {
var startTime = $("#startTime"+number).data("kendoTimePicker");
var endTime = $("#endTime"+number).data("kendoTimePicker");
var timeStartString = kendo.toString(startTime.value(), 'yyyy-MM-dd hh:mm');
var timeEndString = kendo.toString(endTime.value(), 'yyyy-MM-dd hh:mm');
timeStartStrings[number] = timeStartString;
timeEndStrings[number] = timeEndString;
}
However I can't get values for StartTime and EndTime, I always get undefined and I know it's because of $("#startTime"+number).data("kendoTimePicker");
What can I do?
Thanks :)
Is your number-variable in the razor code (top code block) starting initially with -1 (because of .Name("startTime"+(number+1))? Otherwise your javascript code will on its first iteration try to find $("#startTime0") without it existing. This probably leads to an error and thus stopping the execution of the JS-function.
So please check the names existing in your DOM vs the names questioned by Javascript and make sure, that they align properly.

Create a radio button filter based on "Created Date" attribute using jquery or JavaScript

I’m currently loading a number of list items through a customised Content Query Web Part.
And XSLT attribute associated with each of these items is the Created Date.
An example of the mark up below.
<div class="item" createddate="2014-01-22 13:02:52" language="French">Content</div>
<div class="item" createddate="2014-01-28 13:02:52" language="German">Content</div>
<div class="item" createddate="2013-12-18 13:02:52" language="Italian">Content</div>
What I need to do is create a radio button filter where the values are:
Last 30 days
Last 90 days
When either of these radio buttons are selected, it will hide and show the items based on their date value.
How could the filter be created (through jquery/javascript) that would hide and show these items based on their created date?
Any help would be greatly appreciated.
Parse the createddate attribute using new Date(date-time-string), subtract it from today (new Date()), and convert it into days.
Chrome parses your existing date-time format correctly; Firefox currently does not. According to MDN you need to separate the date and time with a T instead of a space. We can make the change in JavaScript if your HTML is immutable:
$('.radioclass').on('change', function (e) {
$radio = $(this);
$('.item').hide().filter(function (i, el) {
var datestr = $(el).attr('createddate').replace(' ', 'T'); //ISO-8601
var createddate = new Date(datestr);
var nowdate = new Date();
// subtracting dates returns a number in milliseconds
var diffdays = Math.floor((nowdate - createddate) / (1000*60*60*24));
return (diffdays <= $radio.val());
}).show();
});
http://jsfiddle.net/mblase75/GBR3t/
I guess you could do some logic with js for this, but why not use jQuery to do so? I'm going to recommend using Moment JS for this. Make sure it is loaded before the script.
With moment we can get the current time and determine if it is before a set date.
var t = moment();
$(document).ready(function() {
$(".items").hide();
var i = t.duration(30, 'd');
var o = t.duration(90, 'd');
var thirtyday = t.add(i);
var ninetyday = t.add(o);
$(".items").each(function() {
var a = $(this).attr("createddate");
var d = moment(a, "YYYY-MM-DD HH:MM:SS");
if(d.isAfter(thirtyday) && d.isBefore(ninetyday)) {
$(this).addClass("lastninetydays").addClass("lastthirtydays");
}
});
});
And then you can show/hide those items with classes based on the radio value.
If you add a time tick, you can get even more dynamic results.
var t = moment();
setInterval(function() {
t = moment();
updateListItems();
radioChange($(".radio").val());
}, 1000);
$(document).ready(function() {
$(".items").hide();
var i = t.duration(30, 'd');
var o = t.duration(90, 'd');
var thirtyday = t.add(i);
var ninetyday = t.add(o);
$(".radio").change(function() {
radioChange($(this).val());
}
});
function updateListItems () {
$(".items").each(function() {
var a = $(this).attr("createddate");
var d = moment(a, "YYYY-MM-DD HH:MM:SS");
if(d.isAfter(thirtyday) && d.isBefore(ninetyday)) {
$(this).addClass("lastninetydays").addClass("lastthirtydays");
}
});
}
function radioChange (val) {
//show/hide list items based on what the radio value is.
}

Using one javascript function for multiple inputs on one form

We have a simple age calculating script, that takes a date input (3 selects - day, month, year) and determine how old. It is triggered by an onChange assigned to the year select.
There are several date inputs scattered through the form, each one set up the same, other than the input names (day1 vs day 1 vs day 3, etc).
Currently we have simply duplicated the js code and manually changed the input variables ...
function Age1()
{
var oldDay = document.step1.day1.value;
var oldMonth = document.step1.month1.value;
var oldYear = document.step1.year1.value;
and more script....
function Age2()
{
var oldDay = document.step1.day2.value;
var oldMonth = document.step1.month2.value;
var oldYear = document.step1.year2.value;
and more script....
and so forth.
Ideally we would like to reuse one script, rather than hardcoding one for each instance. I have tried a bunch of ideas to no avail, but the ideal would be to trigger it via: onChange="Age(X);" and then have the js insert the proper variable:
function Age(varX)
{
var oldDay = document.step1.dayX.value;
var oldMonth = document.step1.monthX.value;
var oldYear = document.step1.yearX.value;
and so on ....
Any ideas for us ? Thanks in advance
function Age(varX)
{
var oldDay = document.step1['day' + varX].value;
var oldMonth = document.step1['month' + varX].value;
var oldYear = document.step1['year' + varX].value;
}

Categories

Resources