How to identify changed cell in onChange function - google-apps-script

I am trying to detect background color change of two cells. A while back I created the following Google Sheet function and added it as an installable trigger From spreadsheet On change since cell color changes are not detected by on Edit. I thought it worked but I just checked it now, and it is not detecting which cell's background color was changed, Any ideas?
function onChangeInstallable(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeSheetName = activeSheet.getSheetName();
if (activeSheetName == "Settings") {
if(e.changeType == "OTHER"){
// makes it this far ok but following line returns
// #REF! instead of A1 notation of changed cell.
var editedRange = SpreadsheetApp.getActiveRange().getA1Notation();
if (editedRange == 'B43' || editedRange == 'B44'){
setBackgroundColors();
}
}
}
}
Also tried the following, but it returns a "Cell reference out of range" error.
var editedRange = activeSheet.getActiveCell().getA1Notation();

edit: looks like this case is still broken, star issue 3269 to vote for a fix
try var editedRange = activeSheet.getActiveRange().getA1Notation();
the active spreadsheet is already being passed into the function with the e object too, fyi.
var ss = e.source;

Related

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);
}
}

How to set Google Sheets tab color using switch case

I was able to change the color of a tab in Google Sheets using this code I found elsewhere:
function onEdit(e) {
if (e.range.getA1Notation() != 'D1') return
e.source.getActiveSheet()
.setTabColor(e.value == 'Asphalt' ? 'red' : null)
}
However I would like to be able to actually change the tab color based on a range of options using Switch Case. Here is what I have so far but it is not working
function onEdit(e) {
var ss = e.SpreadsheetApp.getActiveSpreadsheet()
var trade = ss.getRange("D1")
switch(trade){
case "Asphalt":
e.setTabColor("0000FF");
break;
case "Cabinetry":
e.setTabColor("FF0000");
break;
default:
e.setTabColor("008000");
}
}
Your very close, a few issues as follows:
var ss = e.SpreadsheetApp.getActiveSpreadsheet()
The e parameter returns an object containing various pieces of information about the edit event.
e.source returns the Spreadsheet object where the edit occurred. So, change to:
var ss = e.source.getActiveSheet(); To get the actual sheet where the edit occurred.
Now that ss is the active sheet var trade = ss.getRange("D1") will get that cell but you need to get the value from that cell. So, change to:
var trade = ss.getRange("D1").getValue(); To get the value in the cell.
In your switch block change the e to ss
function onEdit(e) {
var ss = e.source.getActiveSheet();
var trade = ss.getRange("D1").getValue();
switch(trade){
case "Asphalt":
ss.setTabColor("0000FF");
break;
case "Cabinetry":
ss.setTabColor("FF0000");
break;
default:
ss.setTabColor("008000");
}
}

Delete a row in Google Spreadsheets if color of cell is a certain color

So I've be racking my brain about this one for a while now, not 100% sure why this code isn't working.
I got the code from a previous SO post, from there I changed the script to do what I needed.
function onOpen() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create menu
var menu = [{name: "Evaluate Column J/Call Duration", functionName: "deleteRow"}];
// add to menu
ss.addMenu("Delete Calls Under 1 Minute", menu);
}
function deleteRow() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get active/selected row
var activeRow = ss.getActiveRange().getRowIndex();
// get content column J
var columnJ = ss.getRange("J"+activeRow).getFontColor();
// evaluate whether cell has white text or not
if (columnJ == 'white' || columnJ == '#FFFFFF') {
ss.deleteRow(parseInt(activeRow));
}
}
Basically I have a spreadsheet that's exported from a super archaic call tracking software. Our main issue is that we need to take out any call that's under 1 minute and any duplicates. So, we added conditional formatting for both. This is for getting rid of any 1 minute calls, which in turn should delete the whole row.
Anyone have any idea about this? Thanks guys.
Column j is 10. Colors are in '#ffffff' format. Red is '#ff0000'. This function will delete the row that has the selected color in the selected column.
function jakeDeleteRow(column,color) {
var column = (typeof(column)!='undefined')?column:10;
var color = (typeof(color)!='undefined')?color:'#ff0000;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var rng = ss.getDataRange();
var rngA = rng.getBackgrounds()
for(var i=rngA.length-1;i>-1;i--)
{
if(rngA[i][column-1]==color)
{
sht.deleteRow(i+1);
}
}
}

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.

Is it possible to let onEdit trigger for fontstylechanges? (line-through)

Got here two scripts that change the font color based on line-through, both are working.
- First one can be custom triggered,
- Second is onEdit.
The onEdit has my preference, as it automates things instantly, however onEdit does not see changes when a cell's value is getting line-through yes or no.
So is it possible to let onEdit trigger for fontstylechanges?
function colorlinethrough() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get spreadsheet
var sheet = ss.getSheets()[0]; // Get first Sheet
var range = sheet.getDataRange(); // Get cells
var data = range.getValues(); // Get the cell values
for (var i in data) {
var editrange = sheet.getRange(parseInt(i)+1,2);
if (editrange.getFontLine() == "line-through") {
editrange.setFontColor("#CCCCCC");
}
else {
editrange.setFontColor("#000000");
}
}
};
function onEdit(e) {
var ss = e.source; // Get spreadsheet
var range = ss.getActiveRange();
if (range.getFontLine() == "line-through") {
range.setFontColor("#CCCCCC");
}
else {
range.setFontColor("#000000");
}
};
also put this question on the g+ community https://plus.google.com/104787958270362345970/posts/GTdBoTZR3YF
Spreadsheets has an onChange event that might do the trick here. onEdit is when the data changes and onChange is when the spreadsheet UI itself changes. Give it a shot.
https://developers.google.com/apps-script/understanding_events