Google apps script: reliability issue.. setValue onformsubmit less than consistent - google-apps-script

Hopefully this is a reasonably straight forward question.
Firstly, some context information:
I collect information from a form into a google spreadsheet to record entries to cycle races.
I use the onformsubmit trigger to run some code to do the following;
1) I check how many entries I have by rider Grade and compare these to some pre-set limits
2) Based on the pre-set limits, I work out whether the rider's entry is "provisionally entered" or "waitlisted" (I call this EntryType eg EntryType = 'waitlisted')
3) I populate some variables so as to send a confirmation email, quoting back entry details submitted by the user and advise them whether their entry is waitlisted or not.
4) I write the EntryType alongside the form submitted data in the spreadsheet so I have a record of what EntryType each rider was advised by email.
The code works fine apart from one little issue with step 4 above. Most of the time this works fine but if entries come in close together - eg a couple of seconds apart - step 4 may be left blank. The confirmation email will send, the form data will write to the spreadsheet, just that the "EntryType" will not be written to the spreadsheet alongside the form data.
I suspect that the data from the form for the next record coming in takes precedence and the write function fails without erroring? Just a guess.
Could someone offer some suggestions? I believe this code is very close, unfortunately not bullet proof as yet.
Regards, Colin
function onFormSubmit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var oGradeSubmitted = e.values[13];
var oGradeLevelSubmitted = e.values[14];
// Get the Type of Entry Limits to Apply (Handicap, Scratch or None)
var oRangeLT = ss.getRangeByName("oLimitType");
var oLimitType = oRangeLT.getValue();
//== start ===G R A D E L I M I T =================================================================================
if (oLimitType == 'Scratch') {
// Concatenate Generic Range Name & Grade Submitted to get Specific Ranges Names
var oLimitVar = "oLimit" + oGradeSubmitted; //These are now the LOWER waitlist limits
var oLimitUpper = "oLimitUpper" + oGradeSubmitted; //These are the UPPER waitlist limits
var oCountVar = "oCount" + oGradeSubmitted; //The count is based on grade submitted, not handicapping grade so as to not upset waitlist order
// Get Data from Specific Ranges
// 1) Grade Limit Data
//lower waitlist limits
var oRangeLV = ss.getRangeByName(oLimitVar);
var oLimitData = oRangeLV.getValues();
//upper waitlist limits
var oRangeLVU = ss.getRangeByName(oLimitUpper);
var oLimitDataUpper = oRangeLVU.getValues();
// 2) Grade Count Data
var oRangeCV = ss.getRangeByName(oCountVar);
var oCountData = oRangeCV.getValues();
// Write some Data into the same row as the current form submission data
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses");
var row = sheet.getLastRow();
if (+oCountData >= +oLimitData && +oCountData <= +oLimitDataUpper) {
sheet.getRange(row,18).setValue("Waitlisted");
var oEntryStatus = "Waitlisted";
} else {};
if (+oCountData > +oLimitDataUpper) {
sheet.getRange(row,18).setValue("Waitlisted but doubtful");
var oEntryStatus = "Waitlisted but doubtful";
} else {};
}
}

To get around the concurrency issue you could use the e.range parameter that is passed rather than getLastRow():
var row = e.range.getRow();
https://developers.google.com/apps-script/understanding_events (scroll to bottom)

Related

Better/faster way to pass 50+ values from one Google sheet to another

I'm brand new to App Script, so please forgive my ignorance.
The Google sheet I use to hold student data is so long and unwieldy (50+ columns) that I decided to create another sheet to act as a front-end for data entry. Through hours of tutorial videos + bumbling trial and error, I've come up with a working script that takes values from my data entry form-like sheet ('Students') and passes those values to the first empty row in my destination/container sheet ('Master').
I'm really pleased with how the script working - except for the fact that it is ridiculously slow. Based on what I've read, I think I'm making too many calls to the Sheets API, and I need to figure out how to pass all the values from 'Students' to 'Master' en masse rather than one-by-one, but I don't have the skills to do that, and I can't seem to find an example.
I'm sure there's a really simple, elegant solution. Can anyone help?
Here's a little piece of my code (hopefully it's enough to see the inefficient strategy I'm using):
function submitStudentData(){
var caseloadManager = SpreadsheetApp.getActiveSpreadsheet();
var enterStudents = caseloadManager.getSheetByName('Students');
var masterSheet = caseloadManager.getSheetByName('Master');
var clearFields = enterStudents.getRangeList(['C6:C18', 'C22', 'E6:E18','G6:G14','G20','I6:I14','K6:K16', 'M6:M18']);
var blankRow = masterSheet.getLastRow()+1;
masterSheet.getRange(blankRow,1).setValue(enterStudents.getRange("Z1").getValue()); //Concatenated Student Name
masterSheet.getRange(blankRow,3).setValue(enterStudents.getRange("C6").getValue()); //First Name
masterSheet.getRange(blankRow,2).setValue(enterStudents.getRange("C8").getValue()); //Last Name
masterSheet.getRange(blankRow,4).setValue(enterStudents.getRange("C10").getValue()); //Goes By
masterSheet.getRange(blankRow,6).setValue(enterStudents.getRange("E6").getValue()); //DOB
masterSheet.getRange(blankRow,7).setValue(enterStudents.getRange("E8").getValue()); //Grade
masterSheet.getRange(blankRow,5).setValue(enterStudents.getRange("E10").getValue()); //Student ID
masterSheet.getRange(blankRow,10).setValue(enterStudents.getRange("E14").getValue()); //Last FIE
masterSheet.getRange(blankRow,11).setValue(enterStudents.getRange("Z2").getValue()); //Calculated FIE Due Date
masterSheet.getRange(blankRow,8).setValue(enterStudents.getRange("E12").getValue()); //Last Annual Date[enter image description here][1]
masterSheet.getRange(blankRow,13).setValue(enterStudents.getRange("G6").getValue()); //PD
masterSheet.getRange(blankRow,14).setValue(enterStudents.getRange("G8").getValue()); //SD
masterSheet.getRange(blankRow,15).setValue(enterStudents.getRange("G10").getValue()); //TD
masterSheet.getRange(blankRow,16).setValue(enterStudents.getRange("G3").getValue()); //Concatenated Disabilities
masterSheet.getRange(blankRow,18).setValue(enterStudents.getRange("G12").getValue()); //Program Type
masterSheet.getRange(blankRow,12).setValue(enterStudents.getRange("G14").getValue()); //Evaluation Status
masterSheet.getRange(blankRow,20).setValue(enterStudents.getRange("I6").getValue()); //DYS
masterSheet.getRange(blankRow,21).setValue(enterStudents.getRange("I8").getValue()); //GT
masterSheet.getRange(blankRow,19).setValue(enterStudents.getRange("I10").getValue()); //EB
masterSheet.getRange(blankRow,24).setValue(enterStudents.getRange("I12").getValue()); //ESY
masterSheet.getRange(blankRow,22).setValue(enterStudents.getRange("I14").getValue()); //BIP
masterSheet.getRange(blankRow,29).setValue(enterStudents.getRange("K6").getValue()); //TR
masterSheet.getRange(blankRow,30).setValue(enterStudents.getRange("K8").getValue()); //OT
It goes on and one like this for 52 values before clearing all the fields in 'Students.' It works, but it takes well over a minute to run.
I'm trying to attach a picture of my 'Students' form-like sheet in case my description isn't clear.
Thanks so much for helping a humble special educator who knows not what she's doing. :)
Image of 'Students' form/sheet
Read best practices Even though your data isn't a contiguous range it is part of one so get the whole range with getValues() and use the appropriate indices to access the ones that you want. In the end if will be much faster. You may not want to use setValues to write the data because of other issues like messing up formulas. Avoid the use of setValue() and getValue() whenever possible
function submitStudentData() {
const ss = SpreadsheetApp.getActive();
const ssh = ss.getSheetByName('Students');
const msh = ss.getSheetByName('Master');
const nr = msh.getLastRow() + 1;
const vs = ssh.getRange(nr, 1, ssh.getLastRow(), ssh.getLastColumn()).getValues();
let oA1 = [[vs[0][25], vs[7][2], vs[5][2], vs[9][2], vs[9][4], vs[5][4], vs[7][4], vs[11][4]]];
msh.getRange(msh.getLastRow() + 1, 1, oA1.length, oA[0].length).setValues(oA1);//This line replaces all of the below lines
msh.getRange(nr, 1).setValue(vs[0][25]);//Concatenated Student Name
msh.getRange(nr, 2).setValue(vs[7][2]); //Last Name
msh.getRange(nr, 3).setValue(vs[5][2]); //First Name
msh.getRange(nr, 4).setValue(vs[9][2]); //Goes By
msh.getRange(nr, 5).setValue(vs[9][4]); //Student ID
msh.getRange(nr, 6).setValue(vs[5][4]); //DOB
msh.getRange(nr, 7).setValue(vs[7][4]); //Grade
msh.getRange(nr, 8).setValue(vs[11][4]); //Last Annual Date[enter image description here][1]
You could also do a similar thing by using formulas to map all of the data into a single line or column making it much easier to run the scripts.
Here is the working example. Just complete the mapping array as desrbied in the code. The runtime is below 1 second.
const mapping= [
// enter the array [ sourceRange, destinationRow ] for each cell you want to copy form Students to Master
['Z1',1],
['C6',3],
['C8',2],
['C10',4],
['E6',6]
// ... and so on
]
function submitStudentData() {
console.time('submitStudentData')
const caseloadManager = SpreadsheetApp.getActive();
const enterStudents = caseloadManager.getSheetByName('Students');
const masterSheet = caseloadManager.getSheetByName('Master');
const data = enterStudents.getDataRange().getValues()
const destRow = []
mapping.forEach((m,i)=>{
[rowi,coli] = rangeToRCindex(m[0])
const destRowIndex = m[1] - 1
destRow[destRowIndex] = data[rowi][coli]
})
masterSheet.appendRow(destRow)
console.timeEnd('submitStudentData')
}
function rangeToRCindex(range){
const match = range.match(/^([A-Z]+)(\d+)$/)
if (!match) {
throw new Error(`invalid range ${range}`)
}
const col = letterToColumn(match[1])
const row = match[2]
return [row-1,col-1]
}
function letterToColumn(columnLetters) {
let cl = columnLetters.toUpperCase()
let col = 0
for (let i = 0; i < cl.length; i++) {
col *= 26
col += cl.charCodeAt(i) - 65 + 1
}
return col
}
As Cooper said you want to avoid reading and writing to the sheet(s) as much as possible. (I had the same issue when I started with Google Script)
This means that you should read the whole range into a variable and then write your rows out to the master sheet.
Below is an example of what you could use to avoid the setValue() and getValue() slowness you are experiencing
function submitStudentData(){
var caseloadManager = SpreadsheetApp.getActiveSpreadsheet();
var enterStudents = caseloadManager.getSheetByName('Students');
var masterSheet = caseloadManager.getSheetByName('Master');
var clearFields = enterStudents.getRangeList(['C6:C18', 'C22', 'E6:E18','G6:G14','G20','I6:I14','K6:K16', 'M6:M18']);
var blankRow = masterSheet.getLastRow()+1; //You will not need this
//First we will all the data from the students sheet. This will make and array of arrays [[row],[row],[row]].
studentData = enterStudents.getRange(1,1,enterStudents.getLastRow(),enterStudents.getLastColumn()).getValues()
Logger.log(studentData)
//We are going to build an array of arrays of the data that we want to write back to the master sheet. We will start by creating our first array
writeData = []
//Then we loop through all the student data
for (var i = 0; i < studentData.length; i++) {
Logger.log(studentData[i][0])
//We are selecting data from each row to add to our array. in "studentData[i][0]" the [0] is the column number (remember we are starting with 0)
rowData = []
rowData.push(studentData[i][0])
rowData.push(studentData[i][2])
rowData.push(studentData[i][1])
//Then we send the full row to the first array we made
writeData.push(rowData)
}
Logger.log(writeData)
// Now to write out the data. Normally it would not be a good idea to loop a write like this but this as an atomic operation that google will automatically batch write to the sheet.
for (var i = 0; i < writeData.length; i++) {
masterSheet.appendRow(writeData[i])
}
}
Hope this helps get you started.

Need to get permanent timestamps for a Google Sheets Dashboard

I'm trying to build a dashboard for activities in google sheets, for this i have a page where the students can input the activity name and it status:
Activities page
And i need to get the timestamp for when the activity status has been modified, witch happens in this other page:
dashboard page
Where i'am using the flag to lock the time and date that a get with the now() function.
The problems is: every time the page updates, i lose the timestamp. How can I get it permanently?
You can use Apps Script to achieve your goal:
Use the onEdit
trigger
to check when a certain cell is manually changed.
Check if the cell is from Column Status and get the Row.
Write the TimeStamp in the other Sheet depending on the value of Status
For example:
function onEdit(event){
var editedSheet = event.source.getActiveSheet();
var eRange = event.range;
// If the name is Activities and the column edited is A
if (editedSheet.getName() == "Activities" && eRange.getColumn() == 1){
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var dashboard = sprsheet.getSheetByName("Dashboard");
var dshbValues = dashboard.getRange("B1:L1").getValues(); //Values in Dashboard
//Compare the value introduced with the Values in Dashboard
for (var i = 0; i < dshbValues[0].length; i++){
//If they coincide, write the timestamp in the row edited, correspondent column
if (eRange.getValue() == dshbValues[0][i]){
var timestamp = new Date();
dashboard.getRange(eRange.getRow(), i + 2).setValue(timestamp);
}
}
}
}
Take into account that the first time you will need to manually run the script to give the needed permissions. Also, the values in Activities Column C and Dashboard Column A need to be in the same order for coherence purposes.
References:
Range Class
Get Values
Set values
Date()

Importing Data into a spreadsheet and reading the values with Google Script

We use a master spreadsheet containing all the information of the students. I want to create a UI to capture the marks of each student and write it to a Google Sheet from which I will generate their report cards.
I use the following code to import the data from the master list - the names gets imported correctly, but I cannot seem to pull the values? I just get "undefined"
/**
* A function that inserts a custom menu when the spreadsheet opens to generate the Report Spreadsheet.
*/
function onOpen() {
var menu = [{name: 'Capture Report Data', functionName: 'setUpProgressReport_'}];
SpreadsheetApp.getActive().addMenu('Progress Report', menu);
}
/**
* A set-up function that creates a Report Sheet based on the class selected
*/
function setUpProgressReport_() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Report 1');
var ui = SpreadsheetApp.getUi(),
response = ui.prompt(
'Enter Class',
'Please enter the class you would like to enter marks for',
ui.ButtonSet.OK_CANCEL),
selectedClass = response.getResponseText();
//Import names of learners by selected class from Master Sheet
var cell = sheet.getRange("A1");
cell.setFormula('=QUERY(IMPORTRANGE("1Dxjt6W54e7n2F8a2zlRZV0n-VtCoPZTC2oZgeMPd8mE","MasterList!A1:Z2000"),"SELECT Col1, Col2,Col4 WHERE Col4 contains ' + "'" + selectedClass + "'" + ' Order by Col2 asc")');
// Freezes the first row to be used as headings
sheet.setFrozenRows(1);
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var values = SpreadsheetApp.getActiveSheet().getRange(lastRow, lastColumn).getValues();
Browser.msgBox(values[0][22]);
}
Use SpreadsheetApp.flush() to apply all pending spreadsheet changes before getting the values of cells previously modified by the script.
From https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush()
Spreadsheet operations are sometimes bundled together to improve
performance, such as when doing multiple calls to Range.getValue().
However, sometimes you may want to make sure that all pending changes
are made right away, for instance to show users data as a script is
executing.
Also could be helpful to include a test loop to be sure that the IMPORTRANGE task is complete. This test loop could check every certain amount of time,let say 500 millisecondes if certain change already occurred, in example, the script could get the last row before doing the import and compare it with the last row after it and doing a loop until the last is greater than the first.
An alternative is to use Utilities.sleep(milliseconds) alone. This could work but since the IMPORTRANGE execution time isn't deterministic we can not know for sure how many time is required.
I am no expert but I think I kind of figured out what the problem was... well in theory and maybe not in the correct technical details.
var ss = SpreadsheetApp.getActive() sets the current spreadsheet as the ss value, and this is without the imported data. So referencing this variable actually references the data before it was imported. By creating a seperate function and "refreshing" the var ss = SpreadsheetApp.getActive() solved the issue and I could retrieve data normally.

Copying Data Sheet1 to Sheet2 so you can sort & edit both sheets (google apps script?)

I am working in goggle sheets and think I need to use a google apps script to do what I want, but I am a psychologist at a non-profit University hospital trying to do some good and not a programmer (which probably shows) and I am desperately in need of help. I am trying to set up a series of spreadsheets to track participation in workshops for our treatment method.
1) I have a sheet “Participant_Registration” where basic information is entered
2) I want to transfer information from only the first four columns (A:D) of “Participant_Registration” to a second sheet “Learning_Sessions_Attendance”
3) I am also transferring the same information to a third sheet 'Consultation1_Attendance' – but I need to first filter and select only those people assigned to that group.
Here is a link to a copy of my spreadsheet.
https://docs.google.com/spreadsheets/d/17d0bT4LZOx5cyjSUHPRFgEZTz4y1yEL_tO3gtSJ4UJ8/edit?usp=sharing
More generically this is what I am trying to do. Is this possible in google app scripts? It seems it should be.
1) I have original data in sheet1
2) I want the first four columns (A:D) to transfer to sheet2 (it is fine if I need a trigger variable)
3) I want them to transfer in such a way that if you sort either sheet, the data are still fine (still linked to the right line).
4) Ideally if there is a change to the data in the source sheet (Sheet1) the same change will be made in Sheet2.
5) Ideally this would all happen automatically without human intervention through a script.
Any ideas?? I so need your help. I have been all over the forum, git hub, and done a ton of searches and tried following a lot of examples I saw but nothing works. I really need help.
Here are my sample scripts each with a problem:
//The following code copies a range from sheet1 to sheet2 as I wanted. A problem occurs if after if we copy the data from sheet1 we add data to other columns on sheet2. Later if we sort on some variable (which people are bound to do) if the function is deployed again it will overwrite data meaning the data from sheet1 are not connected to the right individual on sheet2
function CopyRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Participant_Registration");
var range = sheet.getRange("A14:D");
var values = range.getValues();
var target = ss.getSheetByName("Learning_Sessions_Attendance");
var target_range = target.getRange("A10:D");
range.copyTo(target_range);
}
So I tried again. This time I tried to just copy the last edited row from sheet1 to sheet2. This function does not appear to work for me.
function CopyRow2() {
// Get Spreadsheets
var source = SpreadsheetApp.openById("1egn6pnRd6mKMGuQxX_jtgwYDtkuMUv2QJItLdh7aIEs");
var target = SpreadsheetApp.openById("1egn6pnRd6mKMGuQxX_jtgwYDtkuMUv2QJItLdh7aIEs");
// Set Sheets
var source_sheet = source.getSheetByName("Participant_Registration");
var target_sheet = target.getSheetByName("Learning_Sessions_Attendance");
var rowIdx = source_sheet.getActiveRange().getRowIndex();
var rowValues = source_sheet.getRange(rowIdx,1,1,source_sheet.getLastRow()).getValues();
Logger.log(rowValues);
var destValues = [];
destValues.push(rowValues[0][0]);// copy data from col A to col A
destValues.push(rowValues[0][1]);//copy data from col B to col B
destValues.push(rowValues[0][2]);//copy data from col C to col C
destValues.push(rowValues[0][3]);//copy data from col D to col D
var dest=source.getSheets()[4];
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);//update destination sheet with selected values in the right order, the brackets are there to build the 2D array needed to write to a range
}
So I tried again and again. I have lots of examples but none seem to work.
Thanks so much.
Chandra
For that to happen automatically (one sheet's change updating another sheet), you will surely need an "event/trigger" to run a script whenever you change a cell. (that is the "onEdit()" function).
But since scripts are likely to fail sometimes (even when they are perfect, that's because of some Google issues), it's not guaranteed that the sheets will always contain the same data.
But, if I could suggest another way, do not let ID be optional. If that is a real ID (like the person ID card number), create another ID exclusively for working with the sheet.
I have edited your second sheet showing a suggestion of how to do it without using scripts. The only things you must be aware of are:
Do not create two people with the same ID.
You have to insert (only) the ID manually in the second sheet.
The VLOOKUP forumla will search for that ID in the first sheet and return the data in the same line. You can sort any sheet in whatever way you like. As long as you don't change people's IDs.
So, in sheet 2, use this in the First Name, Last Name and Email address:
=vlookup(A10,Participant_Registration!$A:$D,2,false)
=vlookup(A10,Participant_Registration!$A:$D,3,false)
=vlookup(A10,Participant_Registration!$A:$D,4,false)
Just extend this formula downwards
I hope this helps. I would avoid scripting for that at any cost. It would be my last resort. (Scripts also need to be changed if you want to rearrange your sheet, and if not, they might cause trouble, write over existing data...)
I also added a button (insert - drawing) and put a script in it (right button, click down arrow, "transfer? script" -- translated from Portuguese).
If you lock all four columns in sheet2 and lock the ID column in sheet 1, people will not be able to chang IDs and cause mess. They can edit people in sheet 1 and not change the formula in sheet2. Script is not affected by sorting or empty spaces (it adds the person in the first empty row it finds).
I added "named ranges" for the four column headers. (With named ranges, the script can refer to names instead of coordinates, which enables you to rearrange the sheet inserting and deleting columns, or moving them with CUT and paste - but the VLOOKUP formula will need manual update if you rearrange columns).
Here is the code: (it could get better if you manage to create dialog boxes and ask for the person's data inside that dialog, then you could lock everything - and you would need an edit button besides the add).
function AddPerson()
{
var S1Name = "Participant_Registration";
var S2Name = "Learning_Sessions_Attendance";
var ID1Name = "regID";
var ID2Name = "learnID";
//these vars are not used in this script
var FN1Name = "regFirstName";
var FN2Name = "learnFirstName";
var LN1Name = "regLastName";
var LN2Name = "learnLastName";
var Email1Name = "regEmail";
var Email2Name = "learnEmail";
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var Sheet1 = sSheet.getSheetByName(S1Name);
var Sheet2 = sSheet.getSheetByName(S2Name);
var ID1 = getRangeByName(sSheet, Sheet1.getName(), ID1Name);
var ID2 = getRangeByName(sSheet, Sheet2.getName(), ID2Name); Logger.log("ID2: " + ID2.getValue());
var Empty1 = getFirstEmpty(ID1);
var Empty2 = getFirstEmpty(ID2);
var Biggest1 = getBiggestID(ID1); Logger.log("Biggest 1: " + Biggest1);
var Biggest2 = getBiggestID(ID2); Logger.log("Biggest 2: " + Biggest2);
if (Biggest1 !== Biggest2)
Browser.msgBox("Warning: there are IDs in one sheet that are not in the other sheet");
var Biggest;
if (Biggest1 > Biggest2) Biggest = Biggest1;
else Biggest = Biggest2;
Biggest++;
Empty1.setValue(Biggest);
Empty2.setValue(Biggest);
}
function getFirstEmpty(Header)
{
while (Header.getValue() !== "")
{
Header = Header.offset(1,0);
}
return Header;
}
function getBiggestID(Header)
{
var Sheet = Header.getSheet();
var LastRow = Sheet.getLastRow();
var Values = Sheet.getRange(Header.getRow(), Header.getColumn(), LastRow - Header.getRow() + 1).getValues();
var len = Values.length;
var MaxID = 1;
for (var i = 0; i < len; i++)
{
var val = Number(Values[i]);
if (!isNaN(val) && val > MaxID)
MaxID = val;
}
return MaxID;
}
function getRangeByName(spreadSheet, sheetName, rangeName)
{
Logger.log("Trying range: " + "'" + sheetName + "'!" + rangeName);
return spreadSheet.getRangeByName("'" + sheetName + "'!" + rangeName);
}

Google Script to Clear multiple ranges.

I have many spreadsheets that get filled out weekly and closed at the start of the new week. I've written a script to go through and clear out all kinds of ranges in a lot of different sheets. See code below. My question is there a better way to do this instead of having to clear ranges one section at a time and have a million clearContent functions? I cannot figure out how to write a function to clearContent where I can list many ranges all in the same function.
function startWeek() {
var confirm = Browser.msgBox('Did you **Close the Week** first?','Pressing YES will clear your week', Browser.Buttons.YES_NO);
if(confirm=='no'){Logger.log('The user clicked "NO."')};
if(confirm=='yes'){
var sheet = SpreadsheetApp.getActive().getSheetByName('INVOICE LOG');
sheet.getRange('A3:M47').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('DAILY INVENTORY');
sheet.getRange('C5:C8').clearContent();
sheet.getRange('D6:I8').clearContent();
sheet.getRange('C10:I10').clearContent();
sheet.getRange('C13:C16').clearContent();
sheet.getRange('D14:I16').clearContent();
sheet.getRange('C18:I18').clearContent();
sheet.getRange('C21:C24').clearContent();
sheet.getRange('D22:I24').clearContent();
sheet.getRange('C26:I26').clearContent();
sheet.getRange('C29:C32').clearContent();
sheet.getRange('D30:I32').clearContent();
sheet.getRange('C34:I34').clearContent();
sheet.getRange('C37:C40').clearContent();
sheet.getRange('D38:I40').clearContent();
sheet.getRange('C42:I42').clearContent();
sheet.getRange('C45:C48').clearContent();
sheet.getRange('D46:I48').clearContent();
sheet.getRange('C50:I50').clearContent();
sheet.getRange('C55:C58').clearContent();
sheet.getRange('D56:I58').clearContent();
sheet.getRange('C60:I60').clearContent();
sheet.getRange('C63:C66').clearContent();
sheet.getRange('D64:I66').clearContent();
sheet.getRange('C68:I68').clearContent();
sheet.getRange('C71:C74').clearContent();
sheet.getRange('D72:I74').clearContent();
sheet.getRange('C76:I76').clearContent();
sheet.getRange('C79:C82').clearContent();
sheet.getRange('D80:I82').clearContent();
sheet.getRange('C84:I84').clearContent();
sheet.getRange('C87:C90').clearContent();
sheet.getRange('D88:I90').clearContent();
sheet.getRange('C92:I92').clearContent();
sheet.getRange('C95:C98').clearContent();
sheet.getRange('D96:I98').clearContent();
sheet.getRange('C100:I100').clearContent();
sheet.getRange('C105:C108').clearContent();
sheet.getRange('D106:I108').clearContent();
sheet.getRange('C110:I110').clearContent();
sheet.getRange('C113:C116').clearContent();
sheet.getRange('D114:I116').clearContent();
sheet.getRange('C118:I118').clearContent();
sheet.getRange('C121:C124').clearContent();
sheet.getRange('D122:I124').clearContent();
sheet.getRange('C126:I126').clearContent();
sheet.getRange('C129:C132').clearContent();
sheet.getRange('D130:I132').clearContent();
sheet.getRange('C134:I134').clearContent();
sheet.getRange('C137:C140').clearContent();
sheet.getRange('D138:I140').clearContent();
sheet.getRange('C142:I142').clearContent();
sheet.getRange('C145:C148').clearContent();
sheet.getRange('D146:I148').clearContent();
sheet.getRange('C150:I150').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('FOOD INVENTORY');
sheet.getRange('D5:F615').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('LIQUOR INVENTORY');
sheet.getRange('D6:G361').clearContent();
sheet.getRange('E365:G520').clearContent();
sheet.getRange('D524:G573').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('DAILY SALES SHEET');
sheet.getRange('B4:H10').clearContent();
sheet.getRange('B12:H12').clearContent();
sheet.getRange('B14:H20').clearContent();
sheet.getRange('B22:H27').clearContent();
sheet.getRange('B29:H30').clearContent();
sheet.getRange('B33:H34').clearContent();
sheet.getRange('B36:H38').clearContent();
sheet.getRange('B43:H44').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('LAST WEEK INVENTORY');
sheet.getRange('E3:E9').clearContent();
var sheet = SpreadsheetApp.getActive().getSheetByName('SAFE AUDIT');
sheet.getRange('C3:P11').clearContent();
sheet.getRange('C14:P18').clearContent();
sheet.getRange('C22:P22').clearContent();
var destination = SpreadsheetApp.getActiveSpreadsheet();
var name = Browser.inputBox('New Week', 'Enter Pub Name & WE Date (ex. SandwichWE02-02-14)', Browser.Buttons.OK);
destination.rename(name)
};
}
Unfortunately there is not currently a Apps Script method to clear multiple ranges with a single function call.
What you might find a little easier to manage is to instead define one or more data structures (even a simple array) containing the Ranges in question. Then you can clear them all by simply looping over the data structure and calling clearContent() on each Range. This would separate the work of keeping track of your Ranges from the work of clearing them. The data structure might also be useful in other areas of your code.
For better organization, you might also make use of the Spreadsheet.setNamedRange() and Spreadsheet.getNamedRange() functions to assign simple IDs to your Ranges. Note that you cannot give more than one Range the same name.