Goal
I'm trying to execute a piece of code in a Google Spreadsheets modal dialog after pressing a submit button in a form. After the submit button is pressed, I want the dialog to display a loading wheel (I've already made that), then close itself using google.script.host.close()
after a 1.5 second delay (using setTimeout()
for that one).
Previous Attempt
I was able to get it working before without the submit button and without the <form>
element, and instead using onclick attributes on normal buttons, but I wasn't able to have the validation work properly with that solution.
Outcome
What ended up happening was immediately after pressing the submit button, the contents of the modal dialog disappeared and it just stayed open until I had to close it manually, and none of the code that I wanted to be executed was executed. When I used the Inspector to look at the source html for the dialog, the block was completely empty. All that was left was this:
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body></body>
</html>
I tried doing the classic debugging solution of console.log()
. I put a pair of log functions in the submission event handler, one before and one after the e.preventDefault()
. Neither were logged. I can only assume that this means the function wasn't being executed at all.
Desired Solution
I need help identifying what went wrong, or if this is some kind of bug with Google's platform, and how I can improve or fix this (if at all).
Edit 1
I have attempted to use event.preventDefault()
, as has been suggested by the answers given in the linked posts (I have edited the snippet to show how I have attempted to use it). This has not worked, and results in the same outcome described above. (Also elaborated what happened in the outcome).
Code Snippets
The snippets following are (in order) JavaScript, CSS, and HTML.
var x;
let ID = t => document.getElementById(t);
var loader = ID('loader');
document.addEventListener("DOMContentLoaded", () => {
loader.style.visibility = 'visible';
google.script.run.withSuccessHandler(res => {
x = res.arr[1];
google.script.run.callLibraryFunction('CharacterSheetCode.clearClassEdit');
switch (res.arr[0]) {
case 'edit':
ID('class').value = res.arr[2].class;
ID('subclass').value = res.arr[2].subclass;
ID('level').value = res.arr[2].level;
ID('hitdie').value = res.arr[2].hitdie;
ID('spellcasting').value = res.arr[2].spells;
makeEditable();
break;
case 'add':
makeEditable();
break;
}
function makeEditable() {
ID('class').readOnly = false;
ID('subclass').readOnly = false;
ID('level').readOnly = false;
ID('level').max = (20 - res.lvl) + (res.arr[2] ? Number(res.arr[2].level) : 0);
ID('hitdie').readOnly = false;
ID('spellcasting').readOnly = false;
ID('addedit').disabled = false;
ID('remove').disabled = false;
loader.style.visibility = 'hidden';
}
})
.callLibraryFunction("CharacterSheetCode.getClassInfo");
});
ID("form").addEventListener("submit", e => {
e.preventDefault();
loader.style.visibility = 'visible';
var className = ID('class').value,
subclass = ID('subclass').value,
level = ID('level').value,
hitdie = ID('hitdie').value,
spells = ID('spellcasting').value;
if (hitdie % 2 == 0 && hitdie >= 6 && hitdie <= 12) {
setTimeout(() => google.script.host.close(), 1500);
google.script.run.callLibraryFunction("CharacterSheetCode.addEditInfo", [className.trim(), subclass.trim(), level, hitdie, spells, x]);
} else {
alert(`Error: You must use a d6, d8, d10, or d12 as a hit die. A d${hitdie} will not be accepted.`);
loader.style.visibility = 'hidden';
}
}
function removeClass() {
loader.style.visibility = 'visible';
setTimeout(() => google.script.host.close(), 1500);
google.script.run.callLibraryFunction("CharacterSheetCode.addEditInfo", ['', '', '', '', '', x]);
}
.container {
background-color: white;
padding: 15px;
height: 200px;
width: 300px;
font-family: Georgia;
color: black;
font-size: 15px;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
}
input {
border-radius: 1em;
text-align: center;
font-family: Georgia;
font-size: 15px;
}
select {
border-radius: 1em;
font-family: Georgia;
font-size: 15px;
}
button {
border-radius: 1em;
font-family: Georgia;
font-size: 15px;
}
button:active {
filter: brightness(80%);
}
.loader {
border: 5px solid #f3f3f3;
border-radius: 50%;
border-top: 5px solid #3498db;
border-bottom: 5px solid #3498db;
position: absolute;
top: calc(50% - 30px);
left: calc(50% - 30px);
width: 50px;
height: 50px;
z-index: 10;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div id="loader" class="loader" style="visibility: hidden;"></div>
<div id="container" class="container">
<form id="form">
<label for="class">Class</label>
<input type="text" id="class" required readonly="readonly"><br>
<label for="subclass">Subclass</label>
<input type="text" id="subclass" readonly="readonly"><br>
<label for="level">Level</label>
<input type="number" id="level" style="width: 50px;" min="1" max="20" required readonly="readonly" onkeypress="return event.charCode >= 48 && event.charCode <= 57">
<label for="hitdie">Hit Die: d</label>
<input type="number" id="hitdie" style="width: 50px" min="6" max="12" step="2" required readonly="readonly" onkeypress="return event.charCode >= 48 && event.charCode <= 57"><br>
<label for="spellcasting">Spellcasting:</label>
<select id="spellcasting" readonly="readonly">
<option>None</option>
<option>Full</option>
<option>Half</option>
<option>Third</option>
<option>Pact</option>
</select><br>
<button id="addedit" type="submit" disabled>Add/Edit</button><br>
<button id="remove" onclick="removeClass()" disabled>Remove Class</button>
<div>Note: The process of updating the sheet can sometimes take up to 20-40 seconds.</div>
</form>
</div>