Google Sheets Timestamp on change - google-apps-script

What I'm trying to achieve is really simple however I'm super uncomfortable with the Google Sheet Script Editor.
I want the date in a certain cell updated whenever something changes on the active sheet.
That's what I got so far:
//Timestamp on change
function timestampOnChange() {
getActiveCell().setValue(new Date());
}
However, even that already returns error messages :/

Explanation:
You need to create an onChange() trigger of a particular
function which will update a specific cell of the active sheet when the spreadsheet
changes content or structure.
The updateCell() function updates the value of B1 with the current
timestamp of the active sheet.
I would advice you to update a specific sheet instead of the active
sheet by using:
const sh = ss.getSheetByName('Sheet1');
instead of:
const sh = ss.getActiveSheet();
Solution:
In more detail, The createOnChangeTrigger() function will create
the onChange() trigger that will execute updateCell() when there
is a change in the content or structure of the spreadsheet file and in our case the active sheet.
function createOnChangeTrigger(){
const ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("updateCell")
.forSpreadsheet(ss)
.onChange()
.create();
}
function updateCell(){
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
sh.getRange('B1').setValue(new Date());
}
Instructions:
Copy/Paste both functions in the script editor and execute createOnChangeTrigger() only once.
References:
onChange()

From the question:
//Timestamp on change
function timestampOnChange() {
getActiveCell().setValue(new Date());
}
However, even that already returns error messages
The above code returns an error because theres isn't a built-in Google Apps Script function named getActiveCell(). To get the active cell you could use
SpreadsheetApp.getCurrentCell()
or
SpreadsheetApp.getActiveRange()
or if you use an edit event object (let say that it's a assigned to e) you could use e.range
It's worthy to not that if you use setValue(new Date()) on the active cell what ever that was entered on that cell will be overwritten.
On Web Applications, a sister site of Stack Overflow, there a lot of Q/A about timestamps in Google Sheets, actually, there is tag for them ---> https://webapps.stackexchange.com/questions/tagged/google-sheets-timestamp. So far there are 102 questions with this tag.

Related

Creating a backup of data entered into a sheet via Google App Scripts

I have a spreadsheet where users can enter data and then execute a function when clicking on a button. When the button is clicked it logs the time and entered data in a new row on another sheet in that spreadsheet.
To make sure that sheet is not accidentally edited by the users I want to create a non-shared backup of that data.
I import the range to another spreadsheet, but just importing the range means that if the original sheet is edited/erased that data will also be edited/erased, so I wrote the following script to log the changes as they come in.
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var incomingSheet = ss.getSheetByName('Incoming');
var lastRow = incomingSheet.getLastRow();
var incomingData = incomingSheet.getRange(lastRow,1,1,7);
var permanentSheet = ss.getSheetByName('PermanentLog')
var newdataRow = permanentSheet.getLastRow();
incomingData.copyTo(permanentSheet.getRange(newdataRow+1,1));
}
This works when Run from the Apps Script Editor, however, when I enter new data and click the button on the original spreadsheet, it logs the data to the log sheet there, and the range is imported to the 'Incoming' sheet of the new Spreadsheet, but the data is not copied over to the 'Permanent Log' sheet (unless I Run it manually from within the Apps Script Editor). It also works if I remove the ImportRange function from the first sheet and then just manually enter data in on the 'Incoming' sheet.
So does this mean new rows from an Imported Range do not trigger onEdit? What would be the solution? I don't want to run this on a timed trigger, I want to permanently capture each new row of data as it comes in.
Also, am I overlooking a more elegant and simple solution to this whole problem?
Thank you for your time.
This function will copy the data to a new Spreadsheet whenever you edit column 7 which I assume is the last column in your data. It only does it for the sheets that you specify in the names array. Note: you cannot run this from the script editor without getting an error unless you provide the event object which replaces the e. I used an installable onEdit trigger.
The function also appends a timestamp and a row number to the beginning of the archive data row
function onMyEdit(e) {
e.source.toast('entry');//just a toast showing that the function is working for debug purposes
const sh = e.range.getSheet();//active sheet name
const names = ['Sheet1', 'Sheet2'];//sheetname this function operates in
if (~names.indexOf(sh.getName()) && e.range.columnStart == 7) {
const ass = SpreadsheetApp.openById('ssid');//archive spreadsheet
const ash = ass.getSheetByName('PermanentLog');//archive sheet
let row = sh.getRange(e.range.rowStart, 1, 1, 7).getValues()[0];
let ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy/MM/dd HH:mm:ss");//timestamp
row.unshift(ts, e.range.rowStart);//add timestamp and row number to beginning
Logger.log(row);//logs the row for debug purposes
ash.appendRow(row);//appends row to bottom of data with ts and row
}
Logger.log(JSON.stringify(e));
}
Restrictions
Script executions and API requests do not cause triggers to run. For example, calling Range.setValue() to edit a cell does not cause the spreadsheet's onEdit trigger to run.
https://developers.google.com/apps-script/guides/triggers
So yeah, as far as I understand you it can't be done that way.

How to get an IFTTT action in Google Sheets to trigger a script?

I have an IFTTT applet that will update cell C65 in my google sheet. I'd like that sheet to run a function submitData() whenever cell C65 is changed. As many know, however, the onEdit and onChange functions do not trigger from IFTTT actions, only from manual inputs.
I've learned this from searching for answers, and nobody seems to be able to explain a workaround. The strangest thing here is that when I first put it together today, it actually worked perfectly. I then swapped google accounts and made other changes that didn't relate to the code or IFTTT applet and all of a sudden it stopped working entirely, even when switching back to the correct google account.
This is the onEdit code that works for screen inputs but not when my IFTTT enters a value into the cell:
function onEdit(e){
var cellAddress,cellAddressToTestFor;
cellAddressToTestFor = 'C65';
// Get cell edited - If it's C65 then do something
cellAddress = e.range.getA1Notation();
Logger.log('cellAddress: ' + cellAddress);
if (cellAddress === cellAddressToTestFor) {
//To Do - Code here if cell edited is correct
submitData();
};
}
Is there any way to get the IFTTT event to trigger my submitData function?
So the 'on edit' trigger won't work with IFTTT changes, but the 'on change' installable trigger will. However, the event object passed by the On Change trigger does not contain 'range', so there's no way to easily check the edited cell's location. To do so:
function onChange(e){
var cellAddress,cellAddressToTestFor;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeSheetName = activeSheet.getSheetName();
cellAddressToTestFor = 'C65';
// Get cell edited - If it's C65 then do something
cellAddress = activeSheet.getActiveRange().getA1Notation();
Logger.log('cellAddress: ' + cellAddress);
if (cellAddress === cellAddressToTestFor) {
//To Do - Code here if cell edited is correct
submitData();
};
}

Google script to delete rows

when I use the deleteRows function I get the error :
TypeError: Cannot read property 'deleteRows' of null
at clearRange(Code:4:4)
here is my code:
function clearRange() {
var ss = SpreadsheetApp.getActive();
// Rows start at "2" - delete of N rows (400)
ss.deleteRow(2, 400);
}
Can you please help me to solve this issue?
Thanks and regards
Thierry
As Andres has said, your script may not be attached to your sheet, and you will have to go to the sheet in question and click Tools > Script Editor.
However, there are two other possible issues -
The function is named deleteRows and not deleteRow
You're calling deleteRows() on a Spreadsheet object. It is a Sheet function.
If these were the issues, this code should fix it.
function clearRange() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
// Rows start at "2" - delete of N rows (400)
sheet.deleteRows(2, 400);
}
Your ss spreadsheet variable is null which means your script is not bound to any spreadsheet as it should be to use the getActive method. You can create a container bound script following the steps explained here:
To create a bound script, open a Google Sheets, Docs, Slides, or Forms
file, then select Tools > Script editor.

Trouble triggering a macro when a specific cell has a specific value

I'm trying to trigger a google sheet macro / apps script to reformat a sheet when a specific value is entered into a specific cell. I have been working on it to get it to work but without success.
Here is my code;
function onEdit(e) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange('C2');
var cellContent = cell.getValue();
if(cellContent === 'Past campaigns - actual cashflows to date only') {
spreadsheet.getRange('7:12').activate();
spreadsheet.getActiveSheet().hideRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
spreadsheet.getRange('13:13').activate();
}
};
I'm new to macros and apps scripts. I have tried to implement all the suggestions from the following links without success;
How can I get a macro to automatically trigger when a cell reaches a certain value in a Google Sheet?
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/sheets
As #Cooper has said you cannot make a trigger based on a cell value. Only on user changes.
You could try to make the onEdit trigger to execute only inside an if statement. But that's already what you have done.
Try this:
function onEdit(e) {
e.source.toast('Entry');
const sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetname
const X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
It's not necessary to use activate in most scripts and certainly in this one since it has to finish in 30 seconds. They use activate in macros because they are following you actions as you move around the screen. But in a script, generally to don't want to interact with the screen very much because it slows down the script and it doesn't really accomplish anything.
I'm currently using in a script that run when a Spreadsheet opens up because it has a lot rows in it and I want it to go down to the last row. So activate is useful because I don't have to scroll down to the last row every time I open the spreadsheet.
try it this way:
function onEdit(e) {
//e.source.toast('Entry');
var sh=e.range.getSheet();
if(sh.getName()!='Sheet Name')return;//you need to change this sheetnamee
var X=sh.getRange('C2').getValue();
if(X=='Past campaigns - actual cashflows to date only') {
//e.source.toast('flag1');
sh.hideRows(e.range.rowStart,e.range.rowEnd-e.range.rowStart+1);
}
}
I hope you're not trying to run this from the script editor because that's not going to work.

Edit a Google Spreadsheet using Google Apps Script

I am trying to edit a google spreadsheet using google apps script. Basically, I have a cell in the spreadsheet that has the value "Pending Approval" in it. When the script is executed, I want it to change the value in that cell to "Approved". Is there a simple way to do this?
.getRange and .setValue are the methods you will want to use in whatever you are trying to do. This little function will just take the cell notation as the first argument, and then the value you want to set as the second.
function setCellValue(cellName, value) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cell = sheet.getRange(cellName);
cell.setValue(value);
}
setCellValue("A1","Approved");