DesiLogi Posted May 27, 2022 Report Share Posted May 27, 2022 This thread has parts and answers in other threads, but none of them solve doing this in a Submission form so I thought a new thread that unified this info would be helpful to anyone who needs this kind of solution. @Meekeee has posted a really cool solution for pushing calendar events via download from Caspio to Google, Apple, MS calendars, which is extremely beneficial: https://jekuer.github.io/add-to-calendar-button/ and https://github.com/jekuer/add-to-calendar-button. There's a few issues in using this solution with Caspio, though, that I haven't been able to figure out--mostly when it's deployed in a submission form. The issue is you need to get the user's input from the submission form to populate the values for the exported event's name, description, BeginDateTime, EndDateTime, and Location. On a Details page it's fairly straightforward, using [@field:BeginDate], etc. But the [@field:..] method isn't available on a Submission form, only Authentication fields can be used that way. I've tried using variables to get the field values (and testing with a 'dead' button and alert box confirmed that the values were captured correctly). The problem is I don't know how to use those variables in the event export code that goes into the datapage (there are other files, css, js, etc. that are referenced from elsewhere). This is the code that gets the values and coverts the date/time field to ISO formatting for the export: function getevent(){ var v_name = document.getElementById('InsertRecordTasksTimeline_Title').value; var v_note = document.getElementById('InsertRecordTasksTimeline_Notes').value; var v_location = document.getElementsByName('InsertRecordTasksTimeline_Location')[0].value; Stamp = new Date(document.getElementById('InsertRecordTasksTimeline_CalDate').value); Hours = Stamp.getHours() Mins = Stamp.getMinutes(); v_BeginDate=('' + Stamp.getFullYear() +"-"+ (Stamp.getMonth()+1) + "-" + Stamp.getDate() +"T"+ Hours + ":" + Mins); Stamp2 = new Date(document.getElementById('InsertRecordTasksTimeline_CalEnd').value); Hours = Stamp2.getHours() Mins = Stamp2.getMinutes(); v_EndDate=('' + Stamp2.getFullYear() +"-"+ (Stamp2.getMonth()+1) + "-" + Stamp2.getDate() +"T"+ Hours + ":" + Mins); } This is @Meekeee's code (there's variations, I'm using one that uses a normal button to call it) that creates the button with the event download options: <button id="default-button" name="submitevent">Save/Close</button> <script type="application/javascript"> const config = { "name": "tile of event", "description": "notes for the event", "startDate" : "2022-05-21T10:15", "endDate": "2022-05-21T12:30", "location":"location of event", options: ["Google", "Apple","Microsoft365"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Reminder-Event", } const button = document.querySelector('#default-button') button.addEventListener('click', ()=> atcb_action(config, button) ) </script> The issue is getting the variable values into the " " part of the code. For example, "name": "tile of event", will work with "name": "[@authfield:Company]", but I can't figure out how to use the variables. It would be something like this (but it doesn't work, though): <button id="default-button" name="submitevent">Save/Close</button> <script type="application/javascript"> const config = { var v_name = document.getElementById('InsertRecordTasksTimeline_Title').value; var v_note = document.getElementById('InsertRecordTasksTimeline_Notes').value; var v_location = document.getElementsByName('InsertRecordTasksTimeline_Location')[0].value; Stamp = new Date(document.getElementById('InsertRecordTasksTimeline_CalDate').value); Hours = Stamp.getHours() Mins = Stamp.getMinutes(); v_BeginDate=('' + Stamp.getFullYear() +"-"+ (Stamp.getMonth()+1) + "-" + Stamp.getDate() +"T"+ Hours + ":" + Mins); Stamp2 = new Date(document.getElementById('InsertRecordTasksTimeline_CalEnd').value); Hours = Stamp2.getHours() Mins = Stamp2.getMinutes(); v_EndDate=('' + Stamp2.getFullYear() +"-"+ (Stamp2.getMonth()+1) + "-" + Stamp2.getDate() +"T"+ Hours + ":" + Mins); "name": "v_name", "description": "n_note", "startDate" : "v_BeginDate", "endDate": "v_EndDate", "location":"v_location", options: ["Google", "Apple","Microsoft365"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Reminder-Event", } const button = document.querySelector('#default-button') button.addEventListener('click', ()=> atcb_action(config, button) ) </script> Does anyone know how to integrate the variables with the event export code? This would be a really great solution if it can be worked out. Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 1, 2022 Author Report Share Posted June 1, 2022 Nobody?? Quote Link to comment Share on other sites More sharing options...
Kurumi Posted June 3, 2022 Report Share Posted June 3, 2022 Hi @DesiLogi - for the Start Date and End Date, you should have a separate variable for getting the actual Date and Time. As per their Important reminder:https://github.com/jekuer/add-to-calendar-button#:~:text=Important information The Date should be formatted as YYYY-MM-DD and the time as HH:MM. In this case, you may need to convert the date and time. I have this sample script for converting the date/time and how you will call the variable in the script. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.8/assets/css/atcb.min.css"> <script src="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.8" defer></script> <button type="button" id="default-button">Download Calendar</button> <script type="application/javascript"> const sday = document.getElementById('InsertRecordDATEFIELD').value; const eday = document.getElementById('InsertRecordDATEFIELD').value; const c_sday = new Date(sday).toLocaleDateString('fr-CA'); const c_eday = new Date(eday).toLocaleDateString('fr-CA'); const time_start = new Date(sday); const time_end = new Date(eday); const t_start = time_start.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', }); const t_end = time_end.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', }); const config = { name: "[@field:FIELDNAME]", description: "[@field:FIELDNAME]", startDate: c_sday, endDate: c_eday, startTime: t_start, endTime: t_end, location:"[@field:FIELDNAME]", options: ["iCal","Outlook.com","Yahoo","Apple","Microsoft365","MicrosoftTeams"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Event Test", } const button = document.querySelector('#default-button') button.addEventListener('click', () => atcb_action(config, button)) </script> I hope this helps! Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 3, 2022 Author Report Share Posted June 3, 2022 Hi @Meekeee, Thanks for updating the thread--hopefully I can get this worked out. For some reason I can't get this code to work at all, even when I pasted it into the submission form verbatim (with the Date field changed to my own). A couple things I think that are relevant: -- this line doesn't work in a submission form, as a submission form doesn't allow pulling @field:fieldname values (only @authfield:fieldname on a submission form). name: "[@field:FIELDNAME]", --I tried using the date/time formatting lines you posted but I couldn't get them to work. However, the code I have for getting the Begin/End Date/Time variables does work in the Details/Update form I used this on, putting a date time into ISO format: YYYY-MM-DDTHH:MM which has gone into the calendars without an issue (from Details/Update forms). So I don't think the date/time formatting is the issue. It seems like the issue is the "const" lines that get the values and then put them in the config code. That's not working here--not sure why. Quote Link to comment Share on other sites More sharing options...
Kurumi Posted June 3, 2022 Report Share Posted June 3, 2022 Hi @DesiLogi - as you are using a Submission Form - calling Fieldnames won't work as this is a new data. May I know when do you trigger the script in the form? Is it after submitting data or before? Or it is just a button? As this is used for downloads, all the variables must have data before downloading the file. Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 3, 2022 Author Report Share Posted June 3, 2022 Hi @Meekeee, I'm using your custom button to trigger the script (I couldn't get any other methods to work for some reason--probably a Caspio issue). This is the button: <button id="default-button" name="submitevent3">Save/Close</button>. When clicked it calls the script below, which opens the export buttons overlay. But it ALSO will submit the form after about 3 seconds, whether the user clicked on anything or not: <script type="application/javascript"> const config = { "name": "tile of event", "description": "notes for the event", "startDate" : "2022-05-21T10:15", "endDate": "2022-05-21T12:30", "location":"location of event", options: ["Google", "Apple","Microsoft365"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Reminder-Event", } const button = document.querySelector('#default-button') button.addEventListener('click', ()=> atcb_action(config, button) ) </script> I can get and format the variables for the new info without a problem (I tested the below code with a separate button and alert boxes and the data is correct, and date/time formatted correctly). var v_name = document.getElementById('InsertRecordTasksTimeline_Title').value; var v_note = document.getElementById('InsertRecordTasksTimeline_Notes').value; var v_location = document.getElementsByName('InsertRecordTasksTimeline_Location')[0].value; Stamp = new Date(document.getElementById('InsertRecordTasksTimeline_CalDate').value); Hours = Stamp.getHours() Mins = Stamp.getMinutes(); v_BeginDate=('' + Stamp.getFullYear() +"-"+ (Stamp.getMonth()+1) + "-" + Stamp.getDate() +"T"+ Hours + ":" + Mins); Stamp2 = new Date(document.getElementById('InsertRecordTasksTimeline_CalEnd').value); Hours = Stamp2.getHours() Mins = Stamp2.getMinutes(); v_EndDate=('' + Stamp2.getFullYear() +"-"+ (Stamp2.getMonth()+1) + "-" + Stamp2.getDate() +"T"+ Hours + ":" + Mins); The variables v_name, v_note, v_location, v_BeginDate, and v_EndDate need to be put in "name", "description", "startDate", "endDate", "location", So the issues for getting this to work in a Caspio submission datapage is: a) holding off on submitting the form till the user is done with the calendar event export options b) taking the new data variables (v_name, v_note, v_location, v_BeginDate, and v_EndDate) and putting them in the config code so they are used in the export c) opening the export buttons as normal so the user can choose an export option OR x out of the overlay d) after the user chooses and export option (or x's out), then submit the Caspio submission form as normal. Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 6, 2022 Author Report Share Posted June 6, 2022 Hi @Meekeee, I've almost got the export worked out with a submission form (I got some help from Caspio) and will post that when it's finalized. One question in the meantime--is there a way to reposition the buttons when using the custom button method? The custom button is on the bottom of the submission form and so when the user clicks it the Event Export button options show up below it, mostly out of range. It would be great if the buttons could go vertical above the custom button instead of below. The code I'm using (will update this thread when the last details are done) is const config = { name: v_name, description: v_note, startDate: c_sday, endDate: c_eday, startTime: stime, endTime: etime, location:"World Wide Web", options: ["Google", "Apple","Microsoft365"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Reminder-Event", } const button = document.querySelector('#default-button') button.addEventListener('click', ()=> atcb_action(config, button) ) Is there a line I can put in there to make the export option buttons go vertical up instead of down? Many thanks! Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 7, 2022 Author Report Share Posted June 7, 2022 Ok, with some gracious help from Caspio (thanks Mykee!) I was able to get the variables into the config file. I also figured out how to place the export buttons where I want them on the form (via a hidden button) and to use 2 button options for submission (Save/Close and Save/Add Another). So this solution is almost complete. The last thing it needs it to actually submit the form but ONLY after the user has clicked an Event Export option or X'd out of it. I still don't know how to do that. Once that's worked out I'll post the whole solution in a concise manner so it's easy to replicate. Quote Link to comment Share on other sites More sharing options...
Kurumi Posted June 7, 2022 Report Share Posted June 7, 2022 Hi @DesiLogi - to make the export option buttons go vertical up instead of down, you can call the div atcb_list and configure the top property. You can try this CSS or Style in the Header: .atcb_list { top: 500px !important; } Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 8, 2022 Author Report Share Posted June 8, 2022 Thanks @Meekeee--that really helps with the button list placement. The last thing that needs to happen for this to work on a submission page is for the form to submit after the user has either clicked on an export button or X'd out of the overlay. I've been trying some code at the end of the script but can't get it to work--can you take a look at it to see what's off? function submitCBForm() { document.getElementById("caspioform").submit(); } const button = document.querySelector('.atcb_list,.atcb_bgoverlay'); button.addEventListener('click', submitCBForm) Quote Link to comment Share on other sites More sharing options...
futurist Posted June 8, 2022 Report Share Posted June 8, 2022 Hi @DesiLogi, At the end of your script you can add the ff: function submitCBForm() { document.getElementById("caspioform").submit(); } var intervalId = window.setInterval(function(){ const submitForm = document.querySelector('.atcb_list'); if (submitForm === null) { } else { clearInterval(intervalId); submitForm.addEventListener('click', submitCBForm) } }, 500); The reason behind setting a timer is because the .actb_list element technically does not exist yet until a user clicks on the Save/Close button, so the timer would be responsible in checking if the .actb_list element finally exists, and it checks it every 0.5 seconds. Now, once the Save/Close has finally been clicked, the .actb_list finally exists, then it proceeds with the submit function you have. Hope this helps! Kurumi 1 Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 9, 2022 Author Report Share Posted June 9, 2022 Hi @futurist, Many thanks for this solution--I'd tried a bunch of things and just couldn't get it to work right. The delay of 500 is key, I didn't realize the sequence of creating the .actb_list element. One last thing, though--if the user doesn't choose one of the Export buttons and instead clicks the 'X' to close the overlay, it doesn't submit but still needs to. This is because the user may not want to export the event and just submit it as normal in Caspio. So when the Export overlay opens they'll click 'X' to close the overlay and expect the Caspio form to submit anyway. I tried adding the other classes involved (.actb_click and .actb_bgoverlay) as OR choices but that didn't work. In fact, I substituted each for .actb_list to test and neither of those classes did anything so I don't think using them is the solution. It seems to me that the way to run the Submit code is to check when .actb_list is closed (if it had been opened to begin with). Does that make sense? How would that be included in the submit solution? Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted June 12, 2022 Author Report Share Posted June 12, 2022 @Meekeee or @futurist-- any chance there's a solution to this? I've been trying to figure it out but so far no good. this is the last piece of this puzzle, and if it's not possible to Submit the Caspio form if the user X's out of the export options then the UX is just not going to work. I really hope this is doable after coming this far-- Quote Link to comment Share on other sites More sharing options...
Kurumi Posted June 22, 2022 Report Share Posted June 22, 2022 Hi @DesiLogi - you may try the same code by @futurist. Here's the modified code: <script> function submitCBForm() { document.getElementById("caspioform").submit(); } var intervalId = window.setInterval(function(){ const submitForm = document.querySelector('.atcb_bgoverlay'); const submitForm1 = document.querySelector('.atcb_list'); if (submitForm === null || submitForm1 === null) { } else { clearInterval(intervalId); submitForm.addEventListener('blur', submitCBForm); submitForm1.addEventListener('click', submitCBForm); } }, 500); </script> The blur event fires when an element has lost focus which is the bgoverlay. You may check these links for reference:https://developer.mozilla.org/en-US/docs/Web/API/Window/blur_eventhttps://developer.mozilla.org/en-US/docs/Web/API/Window/focus_event futurist 1 Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted July 8, 2022 Author Report Share Posted July 8, 2022 Hi @Meekeee, Sorry it took so long to get back to this thread but I was finally able to revisit and implement this last piece of the puzzle--perfection! This is exactly what the whole process needed, now it's a really seamless UI for the Caspio user. Many thanks (to @futurist as well) for offering this solution and following up with the necessary tweaks to integrate it into Caspio. Really an excellent calendar solution I imagine a lot of people on Caspio will use. Kurumi and futurist 2 Quote Link to comment Share on other sites More sharing options...
Kurumi Posted July 8, 2022 Report Share Posted July 8, 2022 Hi @DesiLogi - glad to help! Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted August 22, 2022 Author Report Share Posted August 22, 2022 (edited) Hi @Meekeee, The calendar export is working great--one final question (I hope!): how would this be used in a Calendar datapage itself? I have it in a Submission and a Single Record update form but when I use the method in a Calendar datapage (from the main calendar view) it doesn't seem to catch the correct date or times upon export. I think it has something to do with the export not anchoring to the correct record (it seems to go to the last record in the month view record set). The export needs to be date-specific. What I have is the Export button in an HTML block in the Calendar results section: <button type="button" id="default-button" name="submitevent3"><i class="fa fa-calendar-plus-o" aria-hidden="true"></i> Export Event</button> Then I have the config code in the footer: <script> //***EXPORT calendar events const config = { "name":"[@field:TasksTimeline_Title]", "description":"[@field:TasksTimeline_Notes]", "location":"[@field:TasksTimeline_Task_Cat]", "startDate":"[@field:TasksTimeline_CalDateISO]", "endDate":"[@field:TasksTimeline_CalEndISO]", options: [ "Apple", "Google", "iCal|ics file", "Microsoft365", "MicrosoftTeams", "Outlook.com", ], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Reminder-Event", } const button = document.querySelector('#default-button') button.addEventListener('click', ()=> atcb_action(config, button)) </script> The 'TasksTimeline_CalDateISO' fields contain both the date and time, formatted in ISO for export--works perfectly on the Submission and Update forms so I don't think it's that. It seems like the problem is that the config code is not getting the date-specific record that the export button is being clicked from. It defaults to the last record in the recordset. Any idea how to modify this code to pull the specific record the export button is clicked from? If this'll work it'll make a really nice overall calendar UX. Thanks again for all the help with this! Edited August 22, 2022 by DesiLogi put in image of issue Quote Link to comment Share on other sites More sharing options...
Kurumi Posted September 23, 2022 Report Share Posted September 23, 2022 Hi - Good news! Caspio has a new Tech tip called Downloading Appointments to Calendars Using ICS Files. To know more on how to implement it in the DataPage, you can check it here: https://howto.caspio.com/tech-tips-and-articles/advanced-customizations/download-appointments-to-calendars-using-ics-files/@DesiLogi - you may find the solution in this article under Inserting a button to download ICS files from your Calendar Results Page. Hope it helps! DesiLogi 1 Quote Link to comment Share on other sites More sharing options...
22solutions Posted September 26, 2022 Report Share Posted September 26, 2022 @Meekeee I tried the Downloading Appointment to Calendars Using ICS Files tip and I can't get anything to open after clicking button. Here is the error from the console. Any ideas would be greatly appreciated. Quote Link to comment Share on other sites More sharing options...
Kurumi Posted September 30, 2022 Report Share Posted September 30, 2022 Hi @22solutions - what is your code and fields related to the DataPage? What DataPage you were using? Quote Link to comment Share on other sites More sharing options...
futurist Posted January 8, 2023 Report Share Posted January 8, 2023 Hi, sharing in here a script that I found that allows you to check if an element exists (followed by your code if that element in fact exists) instead of using a timer: function waitForElm(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } To use it: waitForElm('.some-class').then((elm) => { console.log('Element is ready'); console.log(elm.textContent); }); Quote Link to comment Share on other sites More sharing options...
Lauren Posted May 4, 2023 Report Share Posted May 4, 2023 On 6/3/2022 at 11:27 AM, Meekeee said: Hi @DesiLogi - for the Start Date and End Date, you should have a separate variable for getting the actual Date and Time. As per their Important reminder:https://github.com/jekuer/add-to-calendar-button#:~:text=Important information The Date should be formatted as YYYY-MM-DD and the time as HH:MM. In this case, you may need to convert the date and time. I have this sample script for converting the date/time and how you will call the variable in the script. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.8/assets/css/atcb.min.css"> <script src="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.8" defer></script> <button type="button" id="default-button">Download Calendar</button> <script type="application/javascript"> const sday = document.getElementById('InsertRecordDATEFIELD').value; const eday = document.getElementById('InsertRecordDATEFIELD').value; const c_sday = new Date(sday).toLocaleDateString('fr-CA'); const c_eday = new Date(eday).toLocaleDateString('fr-CA'); const time_start = new Date(sday); const time_end = new Date(eday); const t_start = time_start.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', }); const t_end = time_end.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', }); const config = { name: "[@field:FIELDNAME]", description: "[@field:FIELDNAME]", startDate: c_sday, endDate: c_eday, startTime: t_start, endTime: t_end, location:"[@field:FIELDNAME]", options: ["iCal","Outlook.com","Yahoo","Apple","Microsoft365","MicrosoftTeams"], timeZone: "currentBrowser", trigger: "click", iCalFileName: "Event Test", } const button = document.querySelector('#default-button') button.addEventListener('click', () => atcb_action(config, button)) </script> I hope this helps! Hi! This is old, but hopefully you see it. I found your post, as I am trying to accomplish an 'add to calendar' button, and using your script the button is not clickable. Nothing happens - can you point me in the right direction to troubleshoot this perhaps? Thanks! Quote Link to comment Share on other sites More sharing options...
DesiLogi Posted May 8, 2023 Author Report Share Posted May 8, 2023 Hi @Lauren, I ended up using a single fields with ISO format that includes markup for delineating the time. There are various reasons for me not using the standard 2 fields (one for date, one for time) because of a lot of other stuff in the existing app, but combining into ISO format works well. In terms of where to start diagnosing, it's hard to say. The code is fairly complex and I had a LOT of problems getting it to finally work with my particular datapage. I ended up having to break it down function by function, to test where the problems were. First, just make sure the fields have the right data in them and then test that Meekee's solution is pulling them correctly (I use 'alerts' placed in successive stages of code to make sure lines are working). After I make sure of the basics (often using a command button that runs the script, for testing) then I'll massage it into the datapage's UI. I realize this is pretty vague--hope it helps find a place to start, though, and good luck! Quote Link to comment Share on other sites More sharing options...
Flowers4Algernon Posted August 31 Report Share Posted August 31 Hello! Just wanted to share this techtip that will allow you to download Calendar events as PDF files: https://howto.caspio.com/tech-tips-and-articles/downloading-calendar-events-as-pdf-files/ Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.