I’m having an issue with my Google Apps Script for handling form submissions that include multiple checkbox selections (parcel ID). Specifically, I need to process all selected checkboxes and send their values to a Google Sheet, but currently, only the first selection is being processed.
Here’s a detailed overview of the problem, along with the relevant code I’m working with:
Problem Description
I have a form that allows users to select multiple checkboxes representing Parcel IDs. When the form is submitted, the selected Parcel IDs should be sent to a Google Sheet, but only the first selected checkbox value is being sent. I need to modify the existing code to ensure that all selected Parcel IDs are processed and recorded in the Google Sheet.
Here is the relevant code.gs
function doPost(e) {
if (e && e.parameter) {
var landowner = e.parameter.landowner ? e.parameter.landowner.toString() : '';
var substation = e.parameter.substation ? e.parameter.substation.toString() : '';
var comment = e.parameter.comment ? e.parameter.comment.toString() : '';
var status = e.parameter.status ? e.parameter.status.toString() : '';
var supervisor = e.parameter.supervisor ? e.parameter.supervisor.toString() : '';
var date = e.parameter.date ? e.parameter.date : '';
var parcelIds = e.parameter.parcelId ? e.parameter.parcelId.split(',') : []; // Split the comma-separated parcel IDs into an array
// Ensure parcelIds is an array
if (!Array.isArray(parcelIds)) {
parcelIds = [parcelIds];
}
// Loop through each parcel ID and add records
for (var i = 0; i < parcelIds.length; i++) {
var parcelId = parcelIds[i].trim(); // Trim any extra whitespace
if (parcelId) {
addRecord(landowner, comment, date, supervisor, parcelId, substation); // Add record to Agent Notes
addToStatuses(landowner, status, date, supervisor, parcelId, substation); // Add record to Statuses
}
}
removeDuplicateStatuses();
var htmlOutput = HtmlService.createTemplateFromFile('DependentSelect');
var subs = getDistinctSubstations();
htmlOutput.message = 'Records Added';
htmlOutput.subs = subs;
return htmlOutput.evaluate();
} else {
return ContentService.createTextOutput("Error: Invalid request parameters");
}
}
function addRecord(landowner, comment, date, supervisor, parcelId, substation) {
var dateObject = new Date(date);
dateObject.setDate(dateObject.getDate() + 1);
var formattedDate = Utilities.formatDate(dateObject, Session.getScriptTimeZone(), "MM/dd/yyyy");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName("Agent Notes");
dataSheet.appendRow([landowner, comment, formattedDate, supervisor, parcelId, substation]);
var backupSS = SpreadsheetApp.openById("...");
var backupCommentsSheet = backupSS.getSheetByName("Comments");
backupCommentsSheet.appendRow([landowner, comment, formattedDate, supervisor, parcelId, substation]);
}
function addToStatuses(landowner, status, date, supervisor, parcelId, substation) {
var dateObject = new Date(date);
dateObject.setDate(dateObject.getDate() + 1);
var formattedDate = Utilities.formatDate(dateObject, Session.getScriptTimeZone(), "MM/dd/yyyy");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var statusSheet = ss.getSheetByName("Statuses");
statusSheet.appendRow([landowner, status, formattedDate, supervisor, parcelId, substation]);
var backupSS = SpreadsheetApp.openById("...");
var backupStatusesSheet = backupSS.getSheetByName("Statuses");
backupStatusesSheet.appendRow([landowner, status, formattedDate, supervisor, parcelId, substation]);
}
Is there anything glaringly obvious I’m missing?
Here is my html side incase there’s something I am missing there
...html stuff
<script src="https://apis.google.com/js/api.js"></script>
<script>
// Function to set the default date to today's date
function setDefaultDate() {
var today = new Date();
var day = today.getDate();
var month = today.getMonth() + 1; // Months are zero indexed
var year = today.getFullYear();
// Format the date as YYYY-MM-DD for the input field
var formattedDate = year + '-' + (month < 10 ? '0' : '') + month + '-' + (day < 10 ? '0' : '') + day;
// Set the default value of the date picker input field directly
var datePicker = document.getElementById("datePicker");
datePicker.setAttribute("value", formattedDate);
// Set the value of the text box to the same date
datePicker.value = formattedDate;
}
function updateSubstations(supervisor) {
google.script.run.withSuccessHandler(function(substations) {
var substationDropdown = document.getElementById("substation");
substationDropdown.innerHTML = "";
var option = document.createElement("option");
option.value = "";
option.text = "";
substationDropdown.appendChild(option);
// Populate Substation dropdown with matching substations
substations.forEach(function(substation) {
var option = document.createElement("option");
option.value = substation;
option.text = substation;
substationDropdown.appendChild(option);
});
// Select the previously selected substation if available
var savedSubstation = localStorage.getItem("substation");
if (savedSubstation && substations.includes(savedSubstation)) {
substationDropdown.value = savedSubstation;
}
}).getDistinctSubstations(supervisor); // Call server function to get matching substations
}
function updateMaxStatusAndLandownerInfo() {
var selectedParcelIds = Array.from(document.querySelectorAll("#parcelIdContainer input[type=checkbox]:checked"))
.map(checkbox => checkbox.value);
if (selectedParcelIds.length > 0) {
// Call updateMaxStatusForParcel with the first selected Parcel ID
updateMaxStatusForParcel(selectedParcelIds[0]);
// Call getLandownerInfo with the first selected Parcel ID
getLandownerInfo(selectedParcelIds[0]);
}
}
function updateParcelInfo(landowner) {
// Trigger search in "Raw Data" worksheet for landowner value
google.script.run.withSuccessHandler(function(parcelIds) {
var parcelIdContainer = document.getElementById("parcelIdContainer");
parcelIdContainer.innerHTML = ""; // Clear previous checkboxes
// Populate Parcel ID checkboxes with matching rows from columns U3:U
parcelIds.forEach(function(parcelId) {
var checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.name = "parcelId";
checkbox.value = parcelId;
checkbox.id = parcelId;
checkbox.addEventListener("change", updateMaxStatusAndLandownerInfo);
var label = document.createElement("label");
label.htmlFor = parcelId;
label.appendChild(document.createTextNode(parcelId));
parcelIdContainer.appendChild(checkbox);
parcelIdContainer.appendChild(label);
parcelIdContainer.appendChild(document.createElement("br"));
});
}).getParcelIdsByLandowner(landowner); // Call server function to get matching parcel IDs
}
function getLandownerInfo(parcel) {
google.script.run.withSuccessHandler(function(landownerInfo) {
document.getElementById("landowner-info-content").innerText = landownerInfo;
}).getLandownerInfo(parcel);
}
function getParcels(substation) {
google.script.run.withSuccessHandler(function(parcels) {
var parcelDropdown = document.getElementById("parcel");
parcelDropdown.innerHTML = "";
var option = document.createElement("option");
option.value = "";
option.text = "";
parcelDropdown.appendChild(option);
// Sort the parcel options alphabetically
parcels.sort().forEach(function(parcel) {
var option = document.createElement("option");
option.value = parcel;
option.text = parcel;
parcelDropdown.appendChild(option);
});
// Update parcel info immediately after selecting a parcel
var selectedParcel = parcelDropdown.value;
updateParcelInfo(selectedParcel);
}).getParcels(substation);
}
function updateMaxStatusForParcel(parcel) {
google.script.run.withSuccessHandler(function(maxStatus) {
var statusDropdown = document.getElementById("status");
statusDropdown.innerHTML = ""; // Clear previous options
// Define status options in the desired order
var statusOptions = ["", "Assigned to Agent", "Outreach", "Negotiating", "Pledged", "Signed", "Dropped"];
// Add options to the dropdown in the defined order
statusOptions.forEach(function(status) {
var option = document.createElement("option");
option.value = status;
option.text = status;
if (status === maxStatus) {
option.selected = true; // Select the option if it matches the max status
}
statusDropdown.appendChild(option);
});
}).getMaxStatusForParcel(parcel);
}
function saveSubmittedValues() {
var supervisor = document.getElementById("supervisor").value;
var substation = document.getElementById("substation").value;
// Save submitted values to local storage
localStorage.setItem("supervisor", supervisor);
localStorage.setItem("substation", substation);
}
function prefillDropdowns() {
// Retrieve saved values from local storage
var supervisor = localStorage.getItem("supervisor");
var substation = localStorage.getItem("substation");
// Pre-fill supervisor dropdown
if (supervisor) {
document.getElementById("supervisor").value = supervisor;
// Trigger the onchange event of supervisor dropdown to update substation dropdown
updateSubstations(supervisor);
}
// Pre-fill substation dropdown
if (substation) {
document.getElementById("substation").value = substation;
// Trigger the onchange event of substation dropdown to populate parcels
getParcels(substation);
}
}
window.onload = function() {
setDefaultDate();
prefillDropdowns();
};
function validateForm() {
var isValid = true;
var supervisor = document.getElementById("supervisor").value;
var substation = document.getElementById("substation").value;
var parcelIdCheckboxes = document.querySelectorAll("#parcelIdContainer input[type=checkbox]:checked");
var status = document.getElementById("status").value;
var date = document.getElementById("datePicker").value;
var comment = document.getElementById("comment").value;
// Collect all selected parcel IDs
var parcelIds = Array.from(parcelIdCheckboxes).map(checkbox => checkbox.value);
// Check if any field is null or blank
if (!supervisor || !substation || parcelIds.length === 0 || !status || !date || !comment) {
document.getElementById("submit-message").innerText = "All fields must be filled.";
return false; // Prevent form submission
}
// Save submitted values to local storage
saveSubmittedValues();
// Set the parcel IDs as a comma-separated string
document.getElementById("parcelId").value = parcelIds.join(',');
// Call server-side function to sort sheets after form submission
google.script.run.withSuccessHandler(function() {
// Form submission will only proceed after sorting is done
document.forms[0].submit();
}).sortSheets();
// Disable form submit button to prevent resubmission
document.getElementById("submit-button").disabled = true;
return false; // Prevent default form submission to wait for sorting
}
// Prevent form resubmission popup on page reload
if (window.history.replaceState) {
window.addEventListener("beforeunload", function () {
window.history.replaceState(null, null, window.location.href);
});
}
</script>
</head>
<body>
<div class="container">
<img src="https://i.imgur.com/16QsZja.png" alt="Header Image" style="width: 100%; max-width: 200px;">
<h1>Daily Contact Form</h1>
<form method="post" action="<?= getUrl() ?>" onsubmit="return validateForm();">
<label><strong>Land Agent</strong></label><br>
<select name="supervisor" id="supervisor" onchange="updateSubstations(this.value)">
<option value=""></option>
<option value="Dan">Dan</option>
<option value="Ian">Ian</option>
<option value="Parker">Parker</option>
<option value="Scott">Scott</option>
</select><br><br>
<label><strong>Substation</strong></label><br>
<select name="substation" id="substation" onchange="getParcels(this.value)">
<option value=""></option>
</select><br><br>
<label><strong>Landowner</strong></label><br>
<select name="landowner" id="parcel" onchange="updateParcelInfo(this.value)">
<!-- Parcel dropdown will be populated dynamically -->
</select><br><br>
<div id="parcelIdContainer">
</div>
<label><strong>Status</strong></label><br>
<select name="status" id="status">
<option value=""></option>
<option value="Assigned to Agent">Assigned to Agent</option>
<option value="Outreach">Outreach</option>
<option value="Negotiating">Negotiating</option>
<option value="Pledged">Pledged</option>
<option value="Signed">Signed</option>
<option value="Dropped">Dropped</option>
</select><br><br>
<label><strong>Date</strong></label><br>
<input type="date" name="date" id="datePicker"><br><br>
<label><strong>Comment</strong></label><br>
<textarea name="comment" id="comment"></textarea><br><br>
<input type="submit" name="submitButton" id="submit-button" value="Submit" />
<span id="submit-message" class="submit-message"></span>
</form>
<div class="landowner-info">
<h2>Landowner Info</h2>
<p id="landowner-info-content"></p> <!-- Display landowner information -->
</div>
</div>
</body>
</html>