Timestamp function - google-apps-script

I tried to create a function that would timestamp a cell. The way I want it to work is: when I turn a cell TRUE (with a checkbox) it fills a cell with text, then the cell right next to it will timestamp when that happens. The problem is that every time I open the sheet, my timestamp function updates to the current date.
It's my first time scripting in this language or in Sheets. I did my best to Google this first but I didn't find anything that quite fit what I was imagining. Anyone willing to help explain what I did wrong and how to fix it?
function timestamp(input){
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var cellRange = sheet.getActiveCell();
var lastCell = cellRange.offset(0, -1);
if( lastCell.getValue() === '' ){
return('')
} else{
return(new Date());
}
}
Also, if anyone has the time, I stripped these from another script I found on here but don't understand what they are needed for, can someone explain their purpose?:
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
I couldn't get the function to run without it.

To put a timestamp when you check you can use onEdit function, for instance
function onEdit(event){
var r = event.source.getActiveRange();
if ((r.getColumn() == 1) && (r.getValue() == true)){
r.offset(0,2).setValue(new Date());
}
}

Related

Apps Script to update Timestamp when data is inserted automatically in google sheet

This code works fine when data is edited in Column 3 or being copy-pasted but if the cursor remains at column 1 at the time of the whole row being copy/pasted, it won't update and secondly, if salesforce sends data to column 3, it doesn't work that time too, please help me here.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var sName = s.getName();
var r = s.getActiveCell();
var row = r.getRow();
var ar = s.getActiveRange();
var arRows = ar.getNumRows()
// Logger.log("DEBUG: the active range = "+ar.getA1Notation()+", the number of rows = "+ar.getNumRows());
if( r.getColumn() == 3 && sName == 'Sheet1') { //which column to watch on which sheet
// loop through the number of rows
for (var i = 0;i<arRows;i++){
var rowstamp = row+i;
SpreadsheetApp.getActiveSheet().getRange('F' + rowstamp.toString()).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm"); //which column to put timestamp in
}
}
}//setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss");
Explanation:
Three important things to know:
As it is also stated in the official documentation, the onEdit triggers are triggered upon user edits. This function won't be triggered by formula nor another script. If salesforce or any other service except for the user, edits column C the onEdit trigger is not going to be activated. Workarounds exist, but these workarounds depend on the context of your specific problem. I would advice you to search or ask a specific question about it.
Regarding the other issue you have, you should get rid of active ranges and take advantage of the event object. This object contains information regarding the edit/edits user made.
As it is recommended by the Best Practices you should not set values in the sheet iteratively but you can to that in one go by selecting a range of cells and set the values. In your case, you want to set the same value in all of the cells in the desired range, hence setValue is used instead of setValues. But the idea is to get rid of the for loop.
Solution:
function onEdit(e) {
var s = e.source.getActiveSheet();
var sName = s.getName();
var ar = e.range;
var row = ar.getRow();
var arRows = ar.getNumRows()
if( ar.getColumn() == 3 && sName == 'Sheet1') {
s.getRange(row,6,arRows).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
Note:
Again, onEdit is a trigger function. You are not supposed to execute it manually and if you do so you will actually get errors (because of the use of the event object). All you have to do is to save this code snippet to the script editor and then it will be triggered automatically upon edits.

Google Sheets Script - Reference a specific cell in a row

I have a sheet where when I change a specific cell to "YES", I need a template sheet to be copied to a new version and named as per the value of a cell on the current row.
I'm having trouble working out how to get the value of the first cell in the row selected. This is what I have so far (I know this is wrong):
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = sheet.getCurrentCell();
if (currentCell = "YES")
{
SpreadsheetApp.getActiveSpreadsheet().toast("New change control sheet added to workbook.","Change Control",15);
var sourceRow = ss.getActiveRange().getRowIndex();
var tabName = ss.getRange(cell,1).getValues();
ss.getSheetByName("CCTemplate").showSheet()
.activate();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.duplicateActiveSheet();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.getActiveSheet().hideSheet();
ss.setActiveSheet(ss.getSheetByName('Copy of CCTemplate'), true);
ss.getActiveSheet().setName("CC" & tabName);
}
}
Any ideas?
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='Your Sheet Name' && e.value=="YES") {
e.source.toast="New change control sheet added to workbook.","Change Control",15);
var tabName=sh.getRange(e.range.rowStart,1).getValue();
var tsh=e.source.getSheetByName('CCTemplate');
var csh=tsh.copyTo(e.source);
csh.setName('CC'+tabName);
}
}
You should avoid using activate in your scripts especially in simple triggers where you have to finish in 30 seconds. I think this code does the same thing that you intended for your code. One significant difference is that I use the information that comes in the event object that comes with the trigger. You should add the code Logger.log(JSON.stringify(e)) and then look at the logs you will see that there is a lot of information available to you which removes the need to run extra functions to get things like a spreadsheet.
Use event objects
onEdit offers among others the event objects range and value which are helpful to retrieve the range that has been edited and its value.
Also
When you want to a cell and compare it against a value, like in if (currentCell = "YES") - you need to retrive its value (either currentCell.getValue() or just event.value) and you need to use == instead of = for comparison.
Be careful with getValues() vs getValue(). The former gives you a 2D array and is not necessary if you want to retrieve the value of a single cell.
There is no need to set your sheet to active in order to change its name.
You can rewrite your code as following:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = event.range;
var value = event.value;
if (value == "YES")
{
...
var sourceRow = range.getRowIndex();
var tabName = ss.getRange(sourceRow, 1).getValue();
...
ss.getSheetByName('Copy of CCTemplate').setName("CC" + tabName);
}
}

Need trigger to run when change occurs within cell of a certain range

I have a spread sheet where users can update a cell's within Column 'J' with notes, however when they update that cell I need my script to run.
This will then copy all the information from Columns 'I' & 'J', and paste them into another cell, then put a Vlookup formula back into 'J' where it has just taken the information from.
It may sound a complicated way about going around things, but because I have various sheets pulling information from different workbooks I need it to happen in this way.
However I have tried numerous solutions and can not get it to run when a cell is changed.
I have tried a installable on change trigger, but this works on the whole workbook and often ends up deleting the information it should be copying.
I have pasted the code I am working in below, any help would be grateful.
function onChange(e)
{
var editRange = { // J:J
top : 2,
bottom : 2000,
left : 10,
right : 10
};
// Exit if we're out of range
var thisRow = e.range.getRow();
if (thisRow < editRange.top || thisRow > editRange.bottom) return;
var thisCol = e.range.getColumn();
if (thisCol < editRange.left || thisCol > editRange.right) return;
//Where Is The Data Stored That You Want To Copy
var ss = SpreadsheetApp.openById("1ZQLKnCHD9acTXCKpTeOnJshHEz43FDPdKZ-U6Me-k_k")
var West = ss.getSheetByName("West Orders")
var WestNotes = ss.getSheetByName("West Notes")
//Ranges of The Data You Want To Copy
var CopyWestNotes = West.getRange(2, 9,West.getLastRow(),2).getValues()
//Clear The Data Before Overiding
var ClearNotes = WestNotes.getRange(2,1,WestNotes.getLastRow(),2).clear()
//Ranges Of The Data You Want To Store
var PasteWestId = WestNotes.getRange(2,1,West.getLastRow(),2).setValues(CopyWestNotes);
//Put a formula in to update Notes;
var formula = '=IFerror(VLOOKUP(i2,\'West Notes\'!A:B,2,false)," ")'
var WestFormula = West.getRange(2,10,West.getLastRow(),1).setValue(formula)
}
The onEdit event
The change trigger is not a simple trigger. You have to install it yourself. There is also no e.range in this event object. I would guess that if you had checked your executions that you would see some errors.
I modified your code to an onEdit() simple trigger. But you may have to make it installable if you're doing anything that requires permissions. And it looks like you are. So now you should be able to continue debugging your code.
function onEdit(e) {
var editRange = {top:2,bottom:2000,left:10,right:10};
var thisRow=e.range.rowStart;
if (thisRow<editRange.top || thisRow>editRange.bottom)return;
var thisCol=e.range.columnStart;
if (thisCol<editRange.left || thisCol>editRange.right)return;
var ss = SpreadsheetApp.openById("id");
var West = ss.getSheetByName("West Orders");
var WestNotes = ss.getSheetByName("West Notes");
var CopyWestNotes = West.getRange(2, 9,West.getLastRow(),2).getValues();
var ClearNotes = WestNotes.getRange(2,1,WestNotes.getLastRow(),2).clear();
var PasteWestId = WestNotes.getRange(2,1,West.getLastRow(),2).setValues(CopyWestNotes);
var formula = '=IFerror(VLOOKUP(i2,\'West Notes\'!A:B,2,false)," ")';
var WestFormula = West.getRange(2,10,West.getLastRow(),1).setValue(formula);
}
I should have mentioned that you'll need to add the id in line 7.
A simple change to line 7 of the script has eradicated the problem, instead of using .openById, I used .getActiveSpreadsheet

Codes doesn't work in formulated cell (ex. vlookup)

Anyone who can help me with this?
Why my codes wont work in formulated cell?
I want to run my codes in formulated cell like vlookup
Is there a way to solve this problem?
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheets()[0]; // 0 == first sheet.
var ee = ss.getActiveRange().getA1Notation();
if (ee == "A1") { // Check if edited cell is the one we're watching.
if (e.value == "DONE"){ // If the value == "DONE", do stuff.
var toggle = sh.getRange("A1:M1");
for(var i=0;i<50;i++) {
if( i%2 == 0 )
toggle.setBackground("GOLD");
else
toggle.setBackground("WHITE");
SpreadsheetApp.flush();
Utilities.sleep(500);
}
}
}
}
On edit and on change triggers only are fired by changes directly made by the user, not when the result of a formula changes or a change is made by code.
Use conditional formatting instead.

How to set function clearContent() for single cell?

I just wondered why clearContent() function does not work very well in new google spreadsheet!
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("A:L");
var cell = ss.getActiveSelection();
var row = cell.getRow();
var column = cell.getColumn();
var range2 = sheet.getRange(row,column);
var response = Browser.msgBox('Did you confirm it?', Browser.Buttons.YES_NO);
if(response == 'yes'){Browser.msgBox('Thank you!', Browser.Buttons.OK)}
else{range2.clearContent()}
}
When I used old google spreadsheet, it worked.
But I'm using new google spreadsheet. It doesn't work.
getRange('A1:A2').clearContent(); is works.
But getRange(1,2).clearContent(); not work, even though it did work in old google spreadsheet!
Please do not tell me use old google spreadsheet.
Tell me how!!
I don't even see a .getActiveSelection() method in the ss class.
Don't see what you're doing with var range either.
We can just use the passed ss object e to get the range, then clear it when needed.
function onEdit(e) {
var range = e.range;
var response = Browser.msgBox('Did you confirm it?', Browser.Buttons.YES_NO);
if ( response == 'yes' ) {
Browser.msgBox('Thank you!', Browser.Buttons.OK);
}
else {
range.clearContent();
}
}
Thank you for your kind answer.
But I found what the problem is.
In the new google spreadsheet function clearContent() doesn't wotk because of 'data validation'!
So I set remove data validation function and clearcontent, finally, set same data validation in active cell.
It works!
Remove data validation.
Clearcontent.
Set data validation.
If anyone has same problem, try it.