Cell reference out of range, google sheets - google-apps-script

I'm getting this error while running this sheet.
Cell reference out of range (line 81, file "genreportSE")
I don't know why it says it's 'out of range'.
I tried to used 'copyvalues'. I saw a script where you can't really "print" a range, but you can create another spreadsheet, copy that range, then print that sheet and delete it.
How should I accomplish this?
function genreportSE() { // This function let us read the value of a cell from a sheet and change the value of another cell in a different sheet
var ss = SpreadsheetApp.getActive(); //ss stands for spreadsheet, this is the active spreadsheet
var clientsheet = ss.getSheetByName('Clientes SE');
var gensheet = ss.getSheetByName('Generador SE');
var clienttable = clientsheet.getDataRange();
var numberofservices = clienttable.getNumRows(); //The number of services in the Clientes sheet
var error1;
var error2;
var rangetocheck1;
var rangetocheck2;
var client;
var clientname;
var i=0;
var reportswitherrors = []; //Array for faulty reports
var email ='jvaldez#galt.mx';
var subject = "Reporte de producción y consumo - " + (new Date()).toString();
var body = "TEXT" ;
for (i=0;i<=2;i++){
gensheet.getRange('B2').setValue(clientsheet.getRange(i+2,1).getValue()); //This will change the cell "B2" in "Generador SE" to the current service number for the report generation
Utilities.sleep(3000); //A timer to let the importdata function get the data from the SE server in miliseconds
client = gensheet.getRange('B4').getValue;
clientname = String(client);
rangetocheck1 = gensheet.getRange('B8:C14').getValues(); //Data range that could present calculation errors ********
rangetocheck2 = gensheet.getRange('H8:H14').getValues(); //Data range that could present calculation errors ********
if(String(rangetocheck1).indexOf('#N/A') == -1) { //This checks if there are any errors in rangetocheck1
error1 = false;
} else {
error1 = true;
};
if(String(rangetocheck2).indexOf('#N/A') == -1) { //This checks if there are any errors in rangetocheck2
error2 = false;
} else{
error2 = true;
};
if(error1||error2){
reportswitherrors.push(clientsheet.getRange(i+2,1).getValue()); //This appends the current service number to the faulty services array
} else {
// Convert individual worksheets to PDF
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export",15,60);
newSpreadsheet.getSheetByName('Sheet1').activate();
var newsheet = newSpreadsheet.getSheetByName('Sheet1');
var genRange = gensheet.getRange('A1:H50').copyValuesToRange(newsheet,0,10,0,55)
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Weekly Status.pdf',content:pdf, mimeType:'application/pdf'};
MailApp.sendEmail(email, subject, body, {attachments:[attach]});
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
}
};
Logger.log(reportswitherrors);
}

It appears that you've got your row & column dimensions flipped between function calls. (Because Google decided to be inconsistent with the order of them...)
This line calls create(name, rows, columns):
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export",15,60);
You've created a spreadsheet with 15 rows and 60 columns.
A bit further along, probably on line 81, copyValuesToRange(sheet, column, columnEnd, row, rowEnd) gets invoked:
var genRange = gensheet.getRange('A1:H50').copyValuesToRange(newsheet,0,10,0,55)

Related

Auto Refreshing ImportXML Google Sheets

I have a sheet that imports data from a site, there are about 10 imports all slightly different. I want a way that I could update that every five minutes or so. I know there are scrips to do it but when I tried to use one it would just put ?update at the end and mess up the entire import. I can show the script I am using. It is from 4 years ago and maybe it is outdated. Any help would be appreciated.
Also just having a script that changes the = to nothing then adds it back again or something would work I guess.
Here is the script I am using
function RefreshImports() {
var lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) return; // Wait up to 5s for previous refresh to end.
var id = "Sheets ID";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("Sheet Name");
var dataRange = sheet.getDataRange();
var formulas = dataRange.getFormulas();
var content = "";
var now = new Date();
var time = now.getTime();
var re = /.*[^a-z0-9]import(?:xml|data|feed|html|range)\(.*/gi;
var re2 = /((\?|&)(update=[0-9]*))/gi;
var re3 = /(",)/gi;
for (var row=0; row<formulas.length; row++) {
for (var col=0; col<formulas[0].length; col++) {
content = formulas[row][col];
if (content != "") {
var match = content.search(re);
if (match !== -1 ) {
// import function is used in this cell
var updatedContent = content.toString().replace(re2,"$2update=" + time);
if (updatedContent == content) {
// No querystring exists yet in url
updatedContent = content.toString().replace(re3,"?update=" + time + "$1");
}
// Update url in formula with querystring param
sheet.getRange(row+1, col+1).setFormula(updatedContent);
}
}
}
}
// Done refresh; release the lock.
lock.releaseLock();
// Show last updated time on sheet somewhere
sheet.getRange(12,2).setValue("Rates were last updated at " + now.toLocaleTimeString())
}
You can write a script that retrieves the formula from the specified cell and sets it back to the same cell on a timer
For this you need:
Retrieve the formula with getFormula()
Set the formula back into the same cell with getFormula()
Bind an installable time-driven trigger to your function specifying the desired interval
Sample:
function setMeOnTrigger() {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var cell = sheet.getRange("C1");
cell.setFormula(cell.getFormula())
}

I need to split a Google Sheet into multiple tabs (sheets) based on column value

I have searched many possible answers but cannot seem to find one that works. I have a Google Sheet with about 1600 rows that I need to split into about 70 different tabs (with about 20-30 rows in each one) based on the value in the column titled “room”. I have been sorting and then cutting and pasting but for 70+ tabs this is very tedious.
I can use the Query function but I still need to create a new tab, paste the function and update the parameter for that particular tab.
This script seemed pretty close:
ss = SpreadsheetApp.getActiveSpreadsheet();
itemName = 0;
itemDescription = 1;
image = 2;
purchasedBy = 3;
cost = 4;
room = 5;
isSharing = 6;
masterSheetName = "Master";
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Update Purchases')
.addItem('Add All Rows To Sheets', 'addAllRowsToSheets')
.addItem('Add Current Row To Sheet', 'addRowToNewSheet')
.addToUi();
}
function addRowToNewSheet() {
var s = ss.getActiveSheet();
var cell = s.getActiveCell();
var rowId = cell.getRow();
var range = s.getRange(rowId, 1, 1, s.getLastColumn());
var values = range.getValues()[0];
var roomName = values[room];
appendDataToSheet(s, rowId, values, roomName);
}
function addAllRowsToSheets(){
var s = ss.getActiveSheet();
var dataValues = s.getRange(2, 1, s.getLastRow()-1, s.getLastColumn()).getValues();
for(var i = 0; i < dataValues.length; i++){
var values = dataValues[i];
var rowId = 2 + i;
var roomName = values[room];
try{
appendDataToSheet(s, rowId, values, roomName);
}catch(err){};
}
}
function appendDataToSheet(s, rowId, data, roomName){
if(s.getName() != masterSheetName){
throw new Error("Can only add rows from 'Master' sheet - make sure sheet name is 'Master'");
}
var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())];
var roomSheet;
if(sheetNames.indexOf(roomName) > -1){
roomSheet = ss.getSheetByName(roomName);
var rowIdValues = roomSheet.getRange(2, 1, roomSheet.getLastRow()-1, 1).getValues();
for(var i = 0; i < rowIdValues.length; i++){
if(rowIdValues[i] == rowId){
throw new Error( data[itemName] + " from row " + rowId + " already exists in sheet " + roomName + ".");
return;
}
}
}else{
roomSheet = ss.insertSheet(roomName);
var numCols = s.getLastColumn();
roomSheet.getRange(1, 1).setValue("Row Id");
s.getRange(1, 1, 1, numCols).copyValuesToRange(roomSheet, 2, numCols+1, 1, 1);
}
var rowIdArray = [rowId];
var updatedArray = rowIdArray.concat(data);
roomSheet.appendRow(updatedArray);
}
But I always get an unexpected token error on line 51 or 52:
var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())];
(And obviously the column names, etc. are not necessarily correct for my data, I tried changing them to match what I needed. Not sure if that was part of the issue.)
Here is a sample of my data: https://docs.google.com/spreadsheets/d/1kpD88_wEA5YFh5DMMkubsTnFHeNxRQL-njd9Mv-C_lc/edit?usp=sharing
This should return two separate tabs/sheets based on room .
I am obviously not a programmer and do not know Visual Basic or Java or anything. I just know how to google and copy things....amazingly I often get it to work.
Let me know what else you need if you can help.
Try the below code:
'splitSheetIntoTabs' will split your master sheet in to separate sheets of 30 rows each. It will copy only the content not the background colors etc.
'deleteTabsOtherThanMaster' will revert the change done by 'splitSheetIntoTabs'. This function will help to revert the changes done by splitSheetIntoTabs.
function splitSheetIntoTabs() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var header = rows[0];
var contents = rows.slice(1);
var totalRowsPerSheet = 30; // This value will change no of rows per sheet
//below we are chunking the toltal row we have into 30 rows each
var contentRowsPerSheet = contents.map( function(e,i){
return i%totalRowsPerSheet===0 ? contents.slice(i,i+totalRowsPerSheet) : null;
}).filter(function(e){ return e; });
contentRowsPerSheet.forEach(function(e){
//crate new sheet here
var currSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
//append the header
currSheet.appendRow(header);
//populate the rows
e.forEach(function(val){
currSheet.appendRow(val);
});
});
}
// use this function revert the sheets create by splitSheetIntoTabs()
function deleteTabsOtherThanMaster() {
var sheetNotToDelete ='Master';
var ss = SpreadsheetApp.getActive();
ss.getSheets().forEach(function(sheet){
if(sheet.getSheetName()!== sheetNotToDelete)
{
ss.deleteSheet(sheet);
}
});
}
I was using Kessy's nice script, but started having trouble when the data became very large, where the script timed out. I started looking for ways to reduce the amount of times the script read/wrote to the spreadsheet (rather than read/write one row at a time) and found this post https://stackoverflow.com/a/42633934
Using this principle and changing the loop in the script to have a loop within the loop helped reduce these calls. This means you can also avoid the second call to append rows (the "else"). My script is a little different to the examples, but basically ends something like:
`for (var i = 1; i < theEmails.length; i++) {
//Ignore blank Emails and sheets created
if (theEmails[i][0] !== "" && !completedSheets.includes(theEmails[i][0])) {
//Set the Sheet name = email address. Index the sheets so they appear last.
var currentSheet = theWorkbook.insertSheet(theEmails[i][0],4+i);
//append the header
//To avoid pasting formulas, we have to paste contents
headerFormat.copyTo(currentSheet.getRange(1,1),{contentsOnly:true});
//Now here find all the rows containing the same email address and append them
var theNewRows =[];
var b=0;
for(var j = 1; j < rows.length; j++)
{
if(rows[j][0] == theEmails[i][0]) {
theNewRows[b]=[];//Initial new array
theNewRows[b].push(rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7]);
b++;
}
}var outrng = currentSheet.getRange(2,1,theNewRows.length,8); //Make the output range the same size as the output array
outrng.setValues(theNewRows);
I found a table of ~1000 rows timed out, but with the new script took 6.5 secs. It might not be very neat, as I only dabble in script, but perhaps it helps.
I have done this script that successfully gets each room and creates a new sheet with the corresponding room name and adding all the rows with the same room.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// This var will contain all the values from column C -> Room
var columnRoom = sheet.getRange("C:C").getValues();
// This var will contain all the rows
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
//Set the first row as the header
var header = rows[0];
//Store the rooms already created
var completedRooms = []
//The last created room
var last = columnRoom[1][0]
for (var i = 1; i < columnRoom.length; i++) {
//Check if the room is already done, if not go in and create the sheet
if(!completedRooms.includes(columnRoom[i][0])) {
//Set the Sheet name = room (except if there is no name, then = No Room)
if (columnRoom[i][0] === "") {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("No Room");
} else {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(columnRoom[i][0]);
}
//append the header
currentSheet.appendRow(header);
currentSheet.appendRow(rows[i]);
completedRooms.push(columnRoom[i][0])
last = columnRoom[i][0]
} else if (last == columnRoom[i][0]) {
// If the room's sheet is created append the row to the sheet
var currentSheet = SpreadsheetApp.getActiveSpreadsheet()
currentSheet.appendRow(rows[i]);
}
}
}
Please test it and don't hesitate to comment for improvements.

Multiple checkboxes as input in form passing parameters to run app script working in debugger and not working in web app

I have a web app form powered by Google App script where I can write or erase items to spreadsheet via Ajax, by reading e.parameters; this works as intended.
My form has 4 inputs, and through html I managed to display any element that was inserted to spreadsheet. My app script uses nested IF conditionals to run scripts that will add or erase elements.
My form can succesfully write on spreadsheet, BUT it can only erase one item at a time, to achieve erasing elements I use checkboxes that will change the url parameter to something like this:
/dev?q1=&clearq1=2&clearq1=3&q2=&q3=&q4=
My objetive is to be able to mark multiple checkboxes to run a script that will loop through my list and erase items based on their identifier.
This depends on JSON.stringify on my URL to get something like this:
["2","3","4"]
I have tested this script from the GAS debugger with dummy data as the JSON string; and does as intended HOWEVER when I test this LIVE on the web app, it does nothing.
I am confident that the JSON string from the e.parameters function is in the correct format, and the e.parameters meets the condition to run this part of the script.
I will appreciate any help.
I simplied my code below, if you need more information please feel free to ask.
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
// If you don't want to expose either GET or POST methods you can comment out the appropriate function
/* function doGet(e){
return handleResponse(e);
} */ /*
function doPost(e){
return handleResponse(e);
}
function handleResponse(e) {
// shortly after my original solution Google announced the LockService[1]
// this prevents concurrent access overwritting data
// [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
// next set where we write the data - you could write to multiple/alternate destinations
// we'll assume header is in row 1 but you can override with header_row in GET/POST data
// more efficient to set values as [][] array than individually
var eraseq1 = e.parameters.clearq1;
var eraseq2 = e.parameters.clearq2;
var eraseq3 = e.parameters.clearq3;
var eraseq4 = e.parameters.clearq4;
var q1item = e.parameters.q1;
var q2item = e.parameters.q2;
var q3item = e.parameters.q3;
var q4item = e.parameters.q4;
var one = ('1');
var params = JSON.stringify(e.parameters.clearq1);
if (eraseq1 > one)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Q1 display list'));
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[1] == eraseq1) {
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++; }}
Utilities.sleep(2500);
if (q1item != (""))
{
var prefix = '\"';
var formattedDate = Utilities.formatDate(new Date(), "GMT-05:00", "MM/dd/yyyy");
var tss = SpreadsheetApp.openById('1N91xMNNJLnb2QKUYMSZuwl_6HzRT0XNwrP4sf779Vkw'); //replace with destination ID
var ts = tss.getSheetByName('Q1 log list'); //replace with destination Sheet tab name
var q1list = tss.getSheetByName('Q1 display list');
var Avals = ts.getRange("B1:B").getValues();
var Alast = Avals.filter(String).length;
var counta = q1list.getRange("B1:B").getValues();
var lastrow = counta.filter(String).length;
var log = (Alast+1)
ts.getRange(Alast+1,1).setValue(formattedDate);
q1list.getRange(lastrow+1,1).setValue(formattedDate);
ts.getRange(Alast+1,2).setValue(log);
q1list.getRange(lastrow+1,2).setValue('=row()');
ts.getRange(Alast+1,3).setValue(q1item);
q1list.getRange(lastrow+1,3).setValue("<li>" + q1item);
q1list.getRange(lastrow+1,4).setValue('=concatenate("<input type=\"\"checkbox\"\" name=\"\"clearq1\"\" value=\"\"\",row(),\"\"\"></button></li>")')
}}
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
} */
This is the function that will loop over my JSON array from URL params and will erase multiple items based on multiple checkboxes being selected.
function doGet(e) {
var params = JSON.stringify(e.parameters.clearq1);
var ss = SpreadsheetApp.getActiveSpreadsheet();
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Q1 display list'));
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var rowsDeleted = 0;
for (var j in params) {
var k = (params[j]); //OK, esta variable nos da el numero de ID's repetidos!
for (var i = 0; i <= numRows - 1; i++) { //De aqui para abajo el script para borrar dependiendo del valor esta en pie.
var row = values[i];
if (row[1] == k) { //La variable de K es cambiante en cada iteración
sheet.deleteRow((parseInt(i)+1) - rowsDeleted);
rowsDeleted++; }}}
};
It works when running a test, and does not work live when using actual parameters.

Create New Sheet with Name Based on Form Submission

In Google Sheets I have a script I'm using to create a new sheet for each Google Form that is submitted. It is supposed to create a new sheet with name based on the last column, column G(which isn't a form submitted column). Then it takes the information from the last row and the heading row and copy it to the first two rows of the created sheet. It also adds formulae to cells to put the info into columns(transpose) and format it based on a created sheet.
Right now it is creating the sheet and copying the formulae and format, but not giving it the proper name or pulling the last row information.
Please help!
~Charles
I have copied the code below:
function onFormSubmit() {
// onFormSubmit
// get submitted data
var ss = SpreadsheetApp.openById(
'...');
var sheet = ss.getSheetByName("Responses");
var headings = sheet.getRange(1,1,1,
sheet.getLastColumn()).getValues();
var lastRow = sheet.getRange(sheet.getLastRow(),1,1,
sheet.getLastColumn()).getValues();
var studentUsername = lastRow[0][6];
// check if username has sheet
if(ss.getSheetByName(studentUsername)){
var userSheet = ss.getSheetByName(studentUsername);
// if not make
} else {
var userSheet = ss.insertSheet(studentUsername);
userSheet.getRange(1,1,1,
headings[0].length).setValues(headings);
}
// copy submitted data to user's sheet
userSheet.appendRow([lastRow]);
userSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
userSheet.appendRow(['=TRANSPOSE(B1:2)']);
userSheet.hideRows(1,2);
userSheet.setColumnWidth(1, 500);
userSheet.setColumnWidth(2, 500);
var FormatSheet = ss.getSheetByName("Format");
var FormatRange = FormatSheet.getRange("a3:b28");
FormatRange.copyFormatToRange(userSheet,1,3,3,28);
}
With some help from the comments and playing around, i figured out the code I need. Big thanks to #Cooper!
Here it is:
function onFormSubmit() {
// onFormSubmit
// get submitted data
var ss = SpreadsheetApp.openById(
'Sheet_ID');
var sheet = ss.getSheetByName("Responses");
var row = sheet.getLastRow();
var Col = sheet.getLastColumn();
var headings = sheet.getRange(1,1,1,
Col).getValues();
var lastRow = sheet.getRange(row, 1, 1, Col);
var studentUsername = sheet.getRange(row, Col).getValue();
// check if username has sheet
if(ss.getSheetByName(studentUsername)){
var userSheet = ss.getSheetByName(studentUsername);
// if not make
} else {
var userSheet = ss.insertSheet(studentUsername);
userSheet.getRange(1,1,1,
headings[0].length).setValues(headings);
}
// copy submitted data to user's sheet
userSheet.appendRow(lastRow.getValues()[0]);
userSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
userSheet.appendRow(['=TRANSPOSE(B1:2)']);
userSheet.hideRows(1,2);
userSheet.setColumnWidth(1, 500);
userSheet.setColumnWidth(2, 500);
var FormatSheet = ss.getSheetByName("Format");
var FormatRange = FormatSheet.getRange("a3:b28");
FormatRange.copyFormatToRange(userSheet,1,3,3,28);
}

Troubleshooting script to amend Google Calendar from Google Sheets

I have a GAS script run from a Google Sheet with two functions. The first function downloads calendar event details in a named calendar between two dates. The name of the calendar, the start date and the end date are read in from cells A2, B2, and C2 respectively. This function is working fine:
//Function to list certain events in your GCalendar.
function listMyEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var calid = sheet.getRange("A2").getValue();
if(calid == null) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid calendar name!');
return;
}
var startTime = sheet.getRange("B2").getValue();
if(startTime == 0) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a start date!');
return;
}
if(isNaN(startTime)) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid start date!');
return;
}
var endTime = sheet.getRange("C2").getValue();
if(endTime == 0) { //If the cell doesn't contain anything send an error prompt
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter an end date');
return;
}
if(isNaN(endTime)) { //If the cell holds text rather than a number then send an error prompt
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid end date!');
return;
}
var calendar = CalendarApp.getCalendarsByName(calid)[0]; //get the calendar name
var events = calendar.getEvents(startTime, endTime);
var data; //declare a variable to hold all the information.
for(var i = 0; i < events.length;i++){
var event = events[i];
data = [
event.getTitle(),
event.getDescription(),
event.getStartTime(),
event.getEndTime(),
event.getLocation(),
event.getId(),
"N"
];
sheet.appendRow(data);
}
sheet.autoResizeColumn(1);
sheet.autoResizeColumn(2);
sheet.autoResizeColumn(3);
sheet.autoResizeColumn(4);
sheet.autoResizeColumn(5);
sheet.autoResizeColumn(6);
sheet.autoResizeColumn(7);
}
The second function tries to read in the event Id from column F, in order to allow individual events to be amended within the sheet before being written back to Google Calendar. However, the script errors on the line calendarEvent.getId() with the error Cannot call method "getId" of undefined. (line 118, file "Code").
I did read that you need to use the .getEventSeriesById() method - but the events aren't in a series! Is it possible to amend individual events with a script or do I need to delete all events and recreate them with amendments? My code for the second function is here:
function amendCalEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 6; // First row of data to process
var numRows = sheet.getLastRow(); // Number of rows to process
//var maxRows = Math.min(numRows,200); //Limit the number of rows to prevent enormous number of event creations
var calid = sheet.getRange("A2").getValue(); //putting the calendar name in double quotes creates double entries. Who knew?
var dataRange = sheet.getRange(startRow, 1, numRows, 7); //startRow, startCol, endRow, endCol
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName(calid)[0]; //get the calendar name
for (i in data) {
var row = data[i];
var title = row[0]; // column A
var desc = row[1]; // column B
var tstart = row[2]; // column C
var tstop = row[3]; // column D
var loc = row[4]; // column E
var evId = row[5]; // column F
var evDelFlag = row[6]; // column G
var event = cal.calendarEvent.getId(evId);
if (evDelFlag == "N" || evDelFlag == "n") {
event.setTitle(title);
event.setDescription(desc);
event.setTime(tstart, tstop);
event.setLocation(loc);
} else {
cal.getId(evId).deleteEvent;
}
}
}
Any help or pointers are most gratefully accepted.
There are some changes you can do in the function amendCalEvents
1.- numRows variable, you are setting the value of getLasRow but you are not subtracting the rows used for the first information (e.g. if you have just 1 calendar and this calendar has one event, when you run the first function it'll add a new row and this variable will have 3 as value.
so when you u call the function getRange, it will bring the information from 3 rows and not just the one that has the information.
2.- a workaround of using the getEventSeriesById, you can probably call again the function getEvents as you did in the first fucntion.
As you are already looping in the for with a similar amount of data you could access the element inside the array o events and set the desired values.
var event = events[i];
3.- to delete the event now you can call:
event.deleteEvent();
Hope this helps