Use onFormSubmit on a sheet to log each form edit - google-sheets-api

I have a form that stores responses on a sheet. The form is set to allow edits.
I need to track each time a user updates their version/copy of the form.
I've tried the following code. I noticed that e.values only seems to contain the new updated values (and the timestamp). I need the 2nd column to also contain the "Forum Name" (column B) value, even if it hasn't updated.
function copyUpdate(e) {
// triggered onFormSubmit
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Log");
// force the 2nd column to always contain "Forum Name" value
var newValues = e.values;
newValues[1] = e.namedValues["Forum Name"][0];
// Output the timestamp, Forum Name & any changed values
sheet.appendRow(newValues);
}
I'm probably making a really basic mistake, but I'm just not seeing it.
Any help would be most appreciated
Be Well

Apparently, e.namedValues also only contains the new edited values.
I had to search the other sheet for a row that matched the timestamp, and then copy that row to the new sheet. :(
TTFN

Related

Google Sheets Script - save as PDF - Get Name from Cell

Ok, I'm 99% there thanks to a lot of other posts about how to do this.
What am I doing?
I have a google form. When that form is completed and the answers are in the respective google sheet I have another tab that has a template (with a bunch of formulas) that auto-populates pay rates for people. The first formula is the name and it is drive off of the Form Responses tab. The following script hides all other sheets, saves the one tab I want to a PDF, in the folder that I want (then unhides the other sheets).
The problem
When I run this as a test it works perfectly. The PDF that drops into the folder is named with the output from the cell E5 (which is a formula) pulling the person's name. However when I set the trigger to when a form answer comes in then everything is right (all the data on the sheet is right) just the name of the file is showing as "Yes". I'm so confused as to why it is "Yes". If I run the script right afterwards it is the name of the person from the cell E5..... Here is my code.
Is the trigger to fast to pull the response? I don't think it can be as the output on the PDF is right.
function topdf() {
var foldersave=DriveApp.getFolderById('1dSOK6bBCRyEO0_fTuuMFH9sNa4wAWYW8');
var d= new Date();
var request = {
"method": "GET",
"headers":{"Authorization": "Bearer "+ScriptApp.getOAuthToken()},
"muteHttpExceptions": true
};
var key='1-e8dhOOZ5zwfeIBSTSH7yFNKgxVTxwqZvqcTNtQUQrA';
var fetch='https://docs.google.com/spreadsheets/d/'+key+'/export?format=pdf&size=letter&portrait=false'
var ss= SpreadsheetApp.getActiveSpreadsheet();
var sheets=ss.getSheets()
var name=ss.getRange("E5").getValue()
sheets[0].hideSheet()
sheets[1].hideSheet()
sheets[2].hideSheet()
sheets[3].hideSheet()
sheets[4].hideSheet()
sheets[5].hideSheet()
sheets[6].hideSheet()
var pdf = UrlFetchApp.fetch(fetch, request);
pdf = pdf.getBlob().setName(name);
var file = foldersave.createFile(pdf)
sheets[0].showSheet()
sheets[1].showSheet()
sheets[2].showSheet()
sheets[3].showSheet()
sheets[4].showSheet()
sheets[5].showSheet()
sheets[6].showSheet()
}
You're calling getRange() E5 from Spreadsheet ss, which may or may not be the sheet you're looking to get the range from. E5 may be yes from an another sheet. Try
ss.getSheetByName('Sheet1').getRange('E5')

Updating a cell value with unknown range (Google SpreadSheets API v4)

So, i've made an application that fetches data from Spreadsheet with a rest api call.
This data is being mapped from the ValueRange object to a list of custom object and cached in the application for 10 minutes.
I'd like to be able to update a single cell of a specified row of which I do not know the range value (for example 'E9') of.
Is there a good way to loop through the items in the spreadsheet and update a cell value where another field value matches?!
public static void UpdateQuantity(string nameToMatch, int quantity)
{
// find row where column A matches nameToMatch
// update value of column B with quantity
// finally clear cache to get the new data
CacheHelper.ClearCache();
}
If else, when iterating through rows in spreadsheet, how do I know the current row number so I would do a REST call to update the specific cell?
Thanks in advance.

How to copy data validation in a relative way, specifically list from range (with or without scripts) Google Sheets

I have created a spread sheet to track appointments. Within this spread sheet I have dynamic dependent drop down lists, so the choice from list 1 will populate the options in list 2. This is as follows:
Cell C2: Client - Client 1 or Client 2. (this is for the use of the example, the actual lists will expand.)
If cell C2 = Client 1 then the address drop down is as below:
Cell C3: Address - Address 1 or Address 2.
If cell C2 = Client 2 then the address drop down is as below:
Cell C3: Address - Address 3 or Address 4.
The data validation for the client list is simple because this is constant and can be copied from column to column. The data validation for the dependent address list, however, can not be copied across multiple columns as it will always refer to column C and lose connection with the relative client list.
The actual data validation for the cell C3 (Address List) is below:
Cell Range = 'DIARY (V-2.1)'!C3
Criteria = 'DIARY (V-2.1)'!C53:C55
The cells C53:C55 are populated by a filter formula which will sort the relevant addresses dependent on the choice of client in cell C2, this in turn populates the address list in C3.
It may be worth noting that I have 10 sets of these appointment slots per column (10 per day) so I have used a filter function for each of these separate appointments so they work independently, but even this is tedious so my need is to be able to copy the column (or just the data validation) from column C onward and have it stay relative to the filter functions in that column.
Please see the below link to the example spreadsheet and this will all make sense! In the example I have copied column C to column D and the data validation for the address list has detached for all ten appointment slots. (permission is free for all to edit.)
https://docs.google.com/spreadsheets/d/1sOlQEzG1D29RaY86YeR1Da--c8t94J-ZAGjv52U4dsY/edit#gid=1950191921
Note: These cells must be drop down lists - list from range - for the functionality of this specific spreadsheet.
If anyone can help with this it would be MASSIVELY appreciated as I have diligently scoured the forums and cannot find a solution. I did see this video (which is way over my head) that seems to accomplish this using java script:
https://www.youtube.com/watch?v=ZiYnuZ8MwgM&feature=youtu.be
Google Sheets does not currently have a built-in solution for copying/filling data validation references or formulas relatively. But somebody already wrote a nice script in this Google Docs forum post. To avoid just a link as an answer, I'm going to copy in the script and instructions here. Credit to AD:AM from Google Docs forum.
How to use their script:
Select a range of cells across which you want to copy a data validation rule, relatively
From the Validation+ custom menu, select the appropriate option (all references relative, columns absolute, or rows absolute)
The validation of the upper-left cell will be copied to the rest of the range
Link to original solution's example Google Sheets with script already included - you can save your own copy and then start using.
Or to recreate from scratch, here is the script.
function onOpen()
{
SpreadsheetApp.getActiveSpreadsheet().addMenu
(
"Validation+",
[
{name: "Copy validation (all relative references)", functionName: "copyValidation"},
{name: "Copy validation (relative rows, absolute columns)", functionName: "copyValidationColumnsAbsolute"},
{name: "Copy validation (absolute rows, relative columns)", functionName: "copyValidationRowsAbsolute"}
]
);
}
function copyValidation(rowsAbsolute, columnsAbsolute)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getActiveRange();
var dv = r.getDataValidations();
var dvt = dv[0][0].getCriteriaType();
if (dvt != SpreadsheetApp.DataValidationCriteria.VALUE_IN_RANGE) return;
var dvv = dv[0][0].getCriteriaValues();
Logger.log(dvv);
for (var i = 0; i < dv.length; i++)
{
for (var j = i ? 0 : 1; j < dv[0].length; j++)
{
dv[i][j] = dv[0][0].copy().withCriteria(dvt, [dvv[0].offset(rowsAbsolute ? 0 : i, columnsAbsolute ? 0 : j), dvv[1]]).build();
}
}
r.setDataValidations(dv);
}
function copyValidationRowsAbsolute()
{
copyValidation(true, false);
}
function copyValidationColumnsAbsolute()
{
copyValidation(false, true);
}
If you only need the relative copy for a single sheet, you can produce an ods with OpenOffice or LibreOffice that has a relative validation. This is done by removing the $ signs. If you then open load that sheet to your google drive and allow it to be converted to a google sheet, data validation range will be relative if you copy it anywhere in the same sheet. It is not relative if you copied it to another sheet in the same workbook or other google spreadsheets.
For example, if you make the validation for A7 to be the three cells to the right, you'll have something like follows:
Once you save it without the $ it is relative. Then when you upload it you have a sheet with relative validations.

What script can I use to make a copy of a sheet each day automatically?

I have google sheet template made for a local business. The template will be used in a store day to day. I need a Script that duplicates the sheet each day automatically so we don't manually have to. I want the sheets to stay in the same spread sheet, but each tab is a new day. The tab i want to be the date of the day. I know i can use a trigger to auto generate but I don't know how to copy the exact template or change the name of the tab autmatically
Try something like this:
function duplicateSpreadSheets() {
var sheetName, sheet, destination, currentDate;
sheetName = "Name of sheet goes here";
sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName(sheetName);
destination = SpreadsheetApp.openById("Spreadsheet ID goes here (the first string of nubmers and letters in the url)");
sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Copy of " + sheetName)
.activate();
currentDate = new Date(Date.now()); //change the format of the date to what you want, DD/MM/YYYY etc.
SpreadsheetApp.getActiveSpreadsheet()
.renameActiveSheet(currentDate)
}
Go to Resources > All your triggers.. and make this function trigger once per day.
Also keep in mind that Google Spreadsheets has a hard limit of 200 sheets per workbook (or used to, not sure if this has changed) so after 200 days this will stop working.

Export Google sheet to pdf without notes

Generally, can you disable Notes in a Google sheet temporarily?
More detail:
I can use GAS to export sheets to PDF, no issue there. But I've added a timestamp function which adds a 'Note' to a cell when it is edited using the OnEdit built in trigger. This is great because I can see when each cell was edited last without messing with revision history.
Unfortunately when I print to PDF, manually or via GAS, I get this ugly last page that includes each comment listed numerically. Anyway around this besides deleting the notes when I want to export? number of pages will be variable so I can't try to remove all but the first page each time.
There's probably a better way, but I would copy the Spreadsheet, delete all notes, export to PDF and delete the copied Spreadsheet.
You can make sure that you add all your "comments" in the same column, and then hide that column(s) before downloading as PDF.
But the best advice is to use the "Comment" feature of Google Sheets, which allows you to add Comments linked to a cell or range, which are not visible when you download as a PDF. You can insert a "comment" by going to the desired cell and from the menu "Insert" choose the item "Comment", or simply right click the cell and choose "Insert Comment".
So, yes, there is not only a way, but multiple ways of doing this. (Sad to see people respond negatively, vaguely or inaccurately without proper knowledge or even trying to solve the problem, understanding the question or attempt an answer).
I Created a simple script to do it for me:
Go to tool->script editor to create it, then copy/paste the code.
After you add the Menu, you need to refresh to see it.
Use: Click on Custom Utilities->Copy No Notes then type in the name of the sheet, it will create "copy of sheet" that has no notes.
Warning: This script deletes a page named "Copy of [sheet]" where [sheet] is the name of the text you type in. (if it exists)
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Utilities').addItem('Copy No Notes', 'copyNoNotes').addToUi();
}
function copyNoNotes(){
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Copy Sheet', 'Source Sheet?', ui.ButtonSet.YES_NO);
if (response.getSelectedButton() == ui.Button.YES) {
var source = response.getResponseText();
var newSheet = SpreadsheetApp.getActive().getSheetByName("Copy of " + source);
if(newSheet != undefined){
SpreadsheetApp.getActive().deleteSheet(newSheet);
}
var sheet = SpreadsheetApp.getActive().getSheetByName(source);
newSheet = sheet.copyTo(SpreadsheetApp.getActive());
newSheet.clearNotes();
}
}