Using the onEdit function to only edit one tab - google-apps-script

I've seen many similar questions like this asked, but I'm still stumped.
I want an onEdit script to only work on a specific tab. I've tried several things but none of them are working correctly.
The tab on my sheet is called 'WEB Graffiti'. I want to run this script on other tabs on my sheet, but the columns are in different orders. I know how to edit the script to edit different columns but I don't know how to make it only work on the specified tab.
Here is the script I'm using.
function onEdit(e) {
if (!e) {
throw new Error(
);
}
indirectTimestamp_(e);
}
/**
* Inserts a timestamp in column T when column B is edited
* and column C contains the value TRUE.
*
* #param {testing} e The onEdit() event object.
*/
function indirectTimestamp_(e) {
if (e.range.columnStart !== 2
|| e.range.offset(0, 1).getDisplayValue() !== 'TRUE') {
return;
}
const timestampCell = e.range.offset(0, 18);
timestampCell.setValue(new Date()).setNumberFormat('mmm" "d" "yyyy');
};
I tried adding
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('WEB Graffiti'), true);
I tried this and several variations in various locations of the script and it was not working properly.

It's not clear if you want to only EDIT WEB Graffiti, or only run the procedure when that WEB Graffiti is EDITED. OnEdit will always run, the only thing you can do is scope it to make changes based on where the edit was conducted.
The below code of yours will only execute the indirect function when the WEB Graffiti sheet is edited.
function onEdit(e) {
var myRange = e.range;
var theSheetName = myRange.getSheet().getName();
if (!e) {
throw new Error(
);
}
if(theSheetName == 'WEB Graffiti'){
indirectTimestamp_(e);
}
}

Do this for Sheet1
function onEdit(e) {
const sh = e.range.getSheet();
if(sh.getName() == "Sheet1") {
//perform rest of your code which is for sheet1
}
}

Related

Updating a query result when cell values change

I have a query in cell I25 of my first sheet in Googlesheets:
=query({SheetsRange("A13:F17")}, "select sum(Col6) where Col1 contains '"&D7&"' ")
The "SheetsRange" is an Appscript function (thanks to the author!) that gets all of the sheet names for me:
/**
 * Returns concatened string range of all the sheets exept current sheet.
 *
 * #param {"A1:B5"} range - Input range as string that gets concatened to the sheetnames.
 * #return {string} all the sheets with range together
 * #customfunction
 */
function SheetsRange(range) {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const currentSheet = ss.getActiveSheet().getName()
const sheets = ss.getSheets()
 
const output = []
 
sheets.forEach(sheet => {
const sheetname = sheet.getName()
console.log(sheetname)
if (sheetname != currentSheet) {
const values = sheet.getRange(range).getValues()
values.forEach(row => {
output.push(row)
})
}
})
 
return output
 
}
Whenever I update a cell in a sheet, the sum in I25 should reflect these changes. However, it only does this when I hit save on the Appscript.
I think I need an onEdit(e) function in order to catch any changes made on the spreadsheet and call the SheetsRange function? however I've not been able to adapt examples I've found to work for me.
For your amusement, my current attempt of using onEdit is:
function onEdit(e) {
if (!e) {
throw new Error('Please do not run the script in the script editor window. It runs automatically when you edit the spreadsheet.');
}
if (e.range.getA1Notation() !== 'F12:F') {
return;
}
SheetsRange();
}
Thank you for any help!
In your situation, how about the following modification?
Modified script:
function onEdit(e) {
if (!e) {
throw new Error('Please do not run the script in the script editor window. It runs automatically when you edit the spreadsheet.');
}
// I modified below script.
const { range, source } = e;
if (range.columnStart != 6 || range.rowStart == 1) {
return;
}
var formula = "SheetsRange";
var tempFormula = "sample";
source.createTextFinder(formula).matchCase(false).matchFormulaText(true).replaceAllWith(tempFormula);
source.createTextFinder(tempFormula).matchFormulaText(true).replaceAllWith(formula);
}
In this modification, when the cells of column "F" is edited, your showing formula of =query({SheetsRange("A13:F17")}, "select sum(Col6) where Col1 contains '"&D7&"' ") is recalculated.
References:
createTextFinder(findText) of Class Spreadsheet
Class TextFinder
You don't really need onEdit() function to do this... you just need to change the concept of the script.
Custom functions do updates the output results while input got changes.
The reason why yours do not update is because your input is a plain text that doesn't change.
If you change the formula into this:
=LAMBDA(SHEETNAMES,RANGE,
LAMBDA(RLEN,CLEN,SROW,SCOL,
LAMBDA(NAMECOUNT,
LAMBDA(ARRAY,
QUERY(ARRAY,"SELECT SUM(Col6) WHERE Col1 CONTAINS'"&D7&"'")
)(
MAKEARRAY(RLEN*NAMECOUNT,CLEN,LAMBDA(R,C,
INDIRECT("'"&INDEX(SHEETNAMES,ROUNDUP(R/RLEN))&"'!R"&IF(MOD(R,RLEN)=0,RLEN+SROW,MOD(R,RLEN)+SROW)&"C"&C+SCOL,FALSE)
))
)
)(COUNTA(SHEETNAMES))
)(
REDUCE(0,REGEXEXTRACT(RANGE,"(\d+)\D+(\d+)"),LAMBDA(A,B,B-A))+1,
REDUCE(0,BYCOL(REGEXEXTRACT(RANGE,"(\D+)\d+:(\D+)"),LAMBDA(COL,COLUMN(INDIRECT(COL&"1")))),LAMBDA(A,B,B-A))+1,
REGEXEXTRACT(RANGE,"\d+")-1,
COLUMN(INDIRECT(REGEXEXTRACT(RANGE,"\D+")&"1"))-1
)
)(getSheetNames(),"A5:B10")
And change the script into this:
function getSheetNames() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const thisSheet = ss.getActiveSheet().getSheetName();
return ss.getSheets().map(sheet => sheet.getSheetName()).filter(name => name!==thisSheet);
}
Instead of using Apps-script to get the values of each sheet, this example only return a list of sheet names with it.
And we uses INDIRECT() in R1C1 format to create the import data array, which since it is a build-in spreadsheet formula, it is always dynamic.
The results should be updated whenever the reference sheets got updated even without onEdit() trigger.

I can't do a 'simple' onEdit function, app script is very new to me

I am extremely new to Google app scripts and I am trying to convert a vba excel spreadsheet over.
Basically, I am first testing functions in a new simple spreadsheet, with the spreadsheet named mycalculator.
I would then like a user to edit to cell C4 which is named distance. and then with that cell change to then update the value in cell C6 which is named conversion with a value of 100.
How do I do this exactly? Needless to say I have tried the code below and without success. Obviously I am trying to compile something from different sources that I have found, but I keep hitting brick walls.
Also, do I need to reference the spreadsheet? Can I not have the script tied to the one sheet only?
With VBA, I was easily able to follow online tutorials, with app script I am struggling to get started.
function onEdit(e) {
var spreadSheet = e.source;
var sheetName = spreadSheet.getActiveSheet().getName();
if(sheetName == 'mycalculator' && 'distance') {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('mycalculator').getRange('conversion').setValue(100);
}
}
I'm not sure why you don't just put a formula in C7 =IF(C4="","",100) but here is an onEdit that will do it.
function onEdit(e) {
try {
let sheet = e.range.getSheet()
if( sheet.getName() === "mycalculator" ) {
if( ( e.range.getRow() === 4 ) && ( e.range.getColumn() === 3 ) ) { // cell C4
sheet.getRange("conversion").setValue(100);
}
}
}
catch(err) {
SpreadsheetApp.getActiveSpreadsheet().toast("onEdit() "+err);
}
}
Here as an alternate solution if you really need to use the named range "distance".
function onEdit(e) {
try {
let sheet = e.range.getSheet()
if( sheet.getName() === "Sheet1" ) {
if( e.range.getA1Notation() === sheet.getRange("distance").getA1Notation() ) { // cell C4
sheet.getRange("conversion").setValue(100);
}
}
}
catch(err) {
SpreadsheetApp.getActiveSpreadsheet().toast("onEdit() "+err);
}
}
For your information there are numerous examples at these sites.
SpreadsheetApp
Advance Sheets Service
Best Practices
javascript Tutorial

Getting a macro to run using checkbox in google sheets

I'm fairly new to google sheets so I apologise in advance if this seems too basic.
My macro seemed to work fine on computers, I assigned it to a 'shape' button but since it needs to also be functional on a ipad, I searched about it and the answer found was to use an onEdit(e) trigger and use checkbox to set it up.
My issue now is that there's no assign button to have the macro attributed to the checkbox when it's checked :')
I have no issue sharing the script if needed because it's a very simple one.
A checkbox is just a True or False value in a cell, checking/unchecking it triggers the onEdit(e) function. You just need to check the location of the checkbox and it's value to execute the macro.
Sample:
function onEdit(e) {
if (e.range.getA1Notation == "A1") {
if (e.range.getValue == true) {
// execute something
}
else {
// execute something else
}
}
}
Given that the code works, CarlosM's provided answer is already almost correct.
I'll just have to combine it together with your macro
Code:
function onEdit(e) {
// Update if your checkBox is located somewhere else
var checkBoxLocation = "A1";
// Change to false if you want to run the macro when checkBox is unticked
var checkBoxCondition = true;
// Since getA1Notation and getValue are both methods
// We need to add () for them to work
if (e.range.getA1Notation() == checkBoxLocation) {
if (e.range.getValue() == checkBoxCondition) {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('D2').activate();
spreadsheet.duplicateActiveSheet();
spreadsheet.getActiveSheet().setName('Estimate ');
spreadsheet.getActiveSheet().setFrozenRows(0);
var sheet = spreadsheet.getActiveSheet();
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).activate();
sheet = spreadsheet.getActiveSheet();
sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns()).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getRange('E7').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Clients List'), true);
spreadsheet.deleteActiveSheet();
spreadsheet.deleteActiveSheet();
spreadsheet.getRange('A39:H39').activate();
}
}
}
The code above does execute your macro if the conditions are met. These conditions are:
The checkBox location is found in variable checkBoxLocation
The checkBox was ticked, this will execute your macro
To quickly check the behavior of the logic of your script, kindly try this one. Make sure to have a checkBox in A1 before trying the code.
Test Code:
function onEdit(e) {
var checkBoxLocation = "A1";
var checkBoxCondition = true;
if (e.range.getA1Notation() == checkBoxLocation) {
var spreadsheet = SpreadsheetApp.getActive();
var cell = spreadsheet.getRange('D2');
if (e.range.getValue() == checkBoxCondition) {
cell.setValue("A1 checkbox is ticked");
}
else {
cell.setValue("A1 checkbox is unticked");
}
}
}

Using an If statement to check if a checkbox in a column of checkboxes is checked, and then run the remaining script

I cannot get the below to work. Any help would be appreciated. I posted a similar post which I had some great assistance with, however when I apply the same concepts here I cannot get it to work. Thank you.
/** #OnlyCurrentDoc */
function onEdit(e) {
//This IF statement ensures that this onEdit macro only runs when cells A1:A2 are edited
if (
e.source.getSheetName() == "Finances 2020" &&
e.range.getColumn() == 1 &&
1<=e.range.getRow()<=2
) {
//Cells A1:A2 are checkboxes. This section ensures the following script only runs when the checkbox is checked (and not when unchecked).
var checkboxtest = e.range.getValue()
if (checkboxtest == true) {
//Some script to test if the above works (by grabbing some text from a cell near by and pasting it into another):
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var test = spreadsheet.getRange(3, 3).getValues();
spreadsheet.getRange('A3').setValues(test);
}
}
}
;
You haven't defined a sheet for getRange(3, 3), so your code is silently failing. Try running just that portion of your script and you'll see what I mean.
function test() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var test = spreadsheet.getRange(3, 3).getValues();
Logger.log(test); // Error: Cannot find method getRange(number,number).
}
You can easily resolve this by defining a sheet. I'm not sure if you want to use the active sheet or not, but I'll assume you do. So your code could look like this, and it works.
/** #OnlyCurrentDoc */
function onEdit(e) {
//This IF statement ensures that this onEdit macro only runs when cells A1:A2 are edited
if (
e.source.getSheetName() == "Finances 2020" &&
e.range.getColumn() == 1 &&
1<=e.range.getRow()<=2
) {
//Cells A1:A2 are checkboxes. This section ensures the following script only runs when the checkbox is checked (and not when unchecked).
var checkboxtest = e.range.getValue()
if (checkboxtest == true) {
//Some script to test if the above works (by grabbing some text from a cell near by and pasting it into another):
var sheet = SpreadsheetApp.getActiveSheet();
var test = sheet.getRange(3, 3).getValues();
sheet.getRange('A3').setValues(test);
}
}
}

Google sheets macro for switching to another sheet based of drop-down selection

Currently building a function where when a certain selection is selected from a drop-down data validation menu, the user is redirected to a different sheet within the workbook. What I currently have does not return an error but also does not do what is intended. Any help would be greatly appreciated.
function gotoselectsheetnosheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(4,3);
var data = range.getValue();
if (data == "Answers")
{
var dinner = ss.getSheetByName('Answers');
dinner.activate();
}
}
please see this image for further clarification
Try this solution.
function onEdit(e) {
if(e.source.getActiveSheet().getName() === "Menu" && e.range.getRow() === 4 && e.range.getColumn() === 3) {
e.source.getSheetByName(e.value).activate();
}
}
This works if you setup an onEdit() trigger.
function gotosheet(e)
{
e.source.getSheetByName(e.value).activate();
}
e.source is the event event objects resource for the spreadsheet object. Look here to learn more about it.
So then the next is getSheetByName(e.value) and e.value is the new value in the cell being edited.
Then the next is activate. And that makes it move to the named sheet. So presumably you have selected the appropriate sheet names in your validation setup.
Validation setup:
When you select one of the two possible selections in the validation drop down that triggers the onEdit trigger and the function takes you to the tab with that name.
Named Range Used in Validation Setup:
OnEdit Trigger Setup: