I have a script that updates calendar events. At this time it takes 4 minutes to run. The majority of rows are past events and do not need updating. I need my script to only update rows that are not hidden. I've been reading a bunch of posts about this and the documentation, I've looked at the row hidden by user stuff and I just don't understand how to implement any of it. Can someone look at my script and tell me how to change it to ignore hidden rows? Here is my sheet.
Here is my script:
function updateEvents() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Working");
const data = sheet.getDataRange().getValues();
// Rows start at 2
Logger.log(sheet.isRowHiddenByUser(2));
if (data.length < 2) {
console.warn("No data to process.");
return;
}
const [headers, ...rows] = data;
const eventIdIndex = headers.indexOf("onCalendar");
const descriptionIndex = headers.indexOf("description");
const locationIndex = headers.indexOf("location");
//NEW STUFF - index of our file
const docUrlIndex = headers.indexOf("docURL");
if (eventIdIndex === -1 || descriptionIndex === -1) {
console.error("Required columns 'onCalendar' or 'Description' are missing.");
return;
}
const calendarIds = [
"bus.transportation@robinson.k12.tx.us",
"c_c17913bb97e7da2d5ea98cb36acd5d216ecae11f6bf8bd044d6d3e85009f8dca@group.calendar.google.com"
];
calendarIds.forEach(calendarId => {
const calendar = CalendarApp.getCalendarById(calendarId);
rows.forEach((row, index) => {
const eventId = row[eventIdIndex];
if (!eventId) return;
try {
const event = calendar.getEventById(eventId);
if (!event) {
console.warn(`onCalendar ${eventId} not found (Row ${index + 2})`);
return;
}
event.setDescription(row[descriptionIndex] || "");
if (locationIndex !== -1) {
event.setLocation(row[locationIndex] || "");
}
//NEW STUFF
if (docUrlIndex !== -1 && row[docUrlIndex] != "") {
//Calendar API event ID is the same as CalendarApp's but it doesnt end with @google.com
const calendarApiEventId = eventId.replace("@google.com", "");
//To avoid creating the whole resource manually, we get our existing event and then edit it later
const resource = Calendar.Events.get(
calendarId,
calendarApiEventId
);
//Adding attachments
resource["attachments"] = [{
fileUrl: row[docUrlIndex],
title: "Original Trip Sheet"
}];
//Updating our event
Calendar.Events.update(
resource,
calendarId,
calendarApiEventId, {
supportsAttachments: true
}
)
}
console.info(`Updated event ID ${eventId} in calendar ${calendarId} (Row ${index + 2})`);
} catch (error) {
console.error(`Failed to update event ID ${eventId} in calendar ${calendarId} (Row ${index + 2}): ${error.message}`);
console.error(`Error details: ${error.stack}`);
}
});
});
}
Following the statement from a now deleted answer to this post. You can prevent hidden rows from being included on things that your program ultimately does, by adding this bit of code:
onst rowIndex = index + 2; // Adding 2 because data starts from row 2 (index 1)
// Skip this row if it's hidden
if (sheet.isRowHiddenByUser(rowIndex)) {
console.log(`Skipping hidden row ${rowIndex}`);
return;
}
This modification uses a conditional statement that checks if a row is hidden and if so, the programs Execute the return statement effectively ignoring that hidden row.
Complete code
function updateEvents() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Working");
const data = sheet.getDataRange().getValues();
// Rows start at 2
Logger.log(sheet.isRowHiddenByUser(2));
if (data.length < 2) {
console.warn("No data to process.");
return;
}
const [headers, ...rows] = data;
const eventIdIndex = headers.indexOf("onCalendar");
const descriptionIndex = headers.indexOf("description");
const locationIndex = headers.indexOf("location");
//NEW STUFF - index of our file
const docUrlIndex = headers.indexOf("docURL");
if (eventIdIndex === -1 || descriptionIndex === -1) {
console.error("Required columns 'onCalendar' or 'Description' are missing.");
return;
}
const calendarIds = [
"<calendar_id_here>",
"<calendar_id_here>"
];
calendarIds.forEach(calendarId => {
const calendar = CalendarApp.getCalendarById(calendarId);
rows.forEach((row, index) => {
const rowIndex = index + 2; // Adding 2 because data starts from row 2 (index 1)
// Skip this row if it's hidden
if (sheet.isRowHiddenByUser(rowIndex)) {
console.log(`Skipping hidden row ${rowIndex}`);
return;
}
const eventId = row[eventIdIndex];
if (!eventId) return;
try {
const event = calendar.getEventById(eventId);
if (!event) {
console.warn(`onCalendar ${eventId} not found (Row ${index + 2})`);
return;
}
event.setDescription(row[descriptionIndex] || "");
if (locationIndex !== -1) {
event.setLocation(row[locationIndex] || "");
}
//NEW STUFF
if (docUrlIndex !== -1 && row[docUrlIndex] != "") {
//Calendar API event ID is the same as CalendarApp's but it doesnt end with @google.com
const calendarApiEventId = eventId.replace("@google.com", "");
//To avoid creating the whole resource manually, we get our existing event and then edit it later
const resource = Calendar.Events.get(
calendarId,
calendarApiEventId
);
//Adding attachments
resource["attachments"] = [
{
fileUrl: row[docUrlIndex],
title: "Original Trip Sheet"
}
];
//Updating our event
Calendar.Events.update(
resource,
calendarId,
calendarApiEventId,
{ supportsAttachments: true }
)
}
console.info(`Updated event ID ${eventId} in calendar ${calendarId} (Row ${index + 2})`);
} catch (error) {
console.error(`Failed to update event ID ${eventId} in calendar ${calendarId} (Row ${index + 2}): ${error.message}`);
console.error(`Error details: ${error.stack}`);
}
});
});
}
The sample output below is not a completely accurate representation of how your code works but this demonstrates the program successfully ignoring a hidden row.
Sample Output
No hidden row
With hidden row
References: Conditional Statement