I have a function which opens a Sidebar containing a message and music. This function works perfectly but i would like the function showSidebar to run when certain cells are edited (C2:E10 on "Sheet2"). I have tried the following code but this still runs the function when an edit is made anywhere in the Spreadsheet.
function onEdit(showSidebar){
var range =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2").getRange(2, 3, 10, 1)
}
Full page of code here:
function onEdit(e){
var range = e.range;
var sheetName = e.source.getActiveSheet().getSheetName();
if ( // C2:E10 on "Sheet2"
sheetName == "Sheet2" &&
range.rowStart >= 2 &&
range.columnStart >= 3 &&
range.rowStart <= 10 &&
range.columnStart <= 5
) {
showSidebar();
// do something
// showSidebar(); // If you want to run the function of showSidebar(), please use this.
}
}
var SIDEBAR_TITLE = 'Dashboard Notification!';
/**
* Adds a custom menu with items to show the sidebar and dialog.
*
* #param {Object} e The event parameter for a simple onOpen trigger.
*/
function onOpen(e) {
SpreadsheetApp.getUi()
.createAddonMenu()
.addItem('Show sidebar', 'showSidebar')
.addToUi();
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* #param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}
/**
* Opens a sidebar. The sidebar structure is described in the Sidebar.html
* project file.
*/
function showSidebar() {
var ui = HtmlService.createTemplateFromFile('Sidebar')
.evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle(SIDEBAR_TITLE);
SpreadsheetApp.getUi().showSidebar(ui);
}
EDIT:
Having copied this script from my test area to live Sheet, the trigger no longer works when the range is edited. Can anyone shed any light on why this may happen
You want to run the script when the cells of "C2:E10" on "Sheet2" are edited.
You are using the OnEdit event trigger of the simple trigger.
If my understanding is correct, how about this sample script? Please think of this as just one of several answers.
Sample script:
function onEdit(e){
var range = e.range;
var sheetName = e.source.getActiveSheet().getSheetName();
if ( // C2:E10 on "Sheet2"
sheetName == "Sheet2" &&
range.rowStart >= 2 &&
range.columnStart >= 3 &&
range.rowStart <= 10 &&
range.columnStart <= 5
) {
// do something
showSidebar(); // If you want to run the function of showSidebar(), please use this.
}
}
When the values which have 3 rows are put to "E10", the values are put to the cells of "E10:E12". In this script, the function is run.
If you don't want to run when the values are out of range, please modify range.rowStart <= 10 && range.columnStart <= 5 to range.rowEnd <= 10 && range.columnEnd <= 5.
Reference:
Event Objects
If I misunderstood your question and this was not the result you want, I apologize.
Added:
If the function includes several methods which are required to authorize, please use the OnEdit event trigger with the installable trigger. https://developers.google.com/apps-script/guides/triggers/installable
At that time, please modify the function name as fullows.
Sample script:
Before you use this script, please install the function of installableOnEdit as the installable trigger of OnEdit event trigger. You can see how to install it at here.
function installableOnEdit(e){ // Modified
var range = e.range;
var sheetName = e.source.getActiveSheet().getSheetName();
if ( // C2:E10 on "Sheet2"
sheetName == "Sheet2" &&
range.rowStart >= 2 &&
range.columnStart >= 3 &&
range.rowStart <= 10 &&
range.columnStart <= 5 && // Modified
"value" in e // Added
) {
showSidebar();
}
}
In this case, the function name was modified from onEdit to installableOnEdit.
When onEdit is installed as the installable trigger, both the simple trigger and the installable trigger are run. By modifying the function name from onEdit to other name, the duplicate running can be prevented.
When the cells of "C2:E10" on "Sheet2" are edited, showSidebar() is run.
And also, when the value is deleted in the range, showSidebar() is NOT run.
Related
I have script for Google Sheets that I collected on interwebs and got some help here. No I have 2 onEdit in conflict. I overcome that by creating script Trigger for onEdit2. It works but I don't think it is the best solution. Could you help get those two separated onEdit with if functions into one, please?
//Dependent Dropdown list
function onEdit(e){ // Function that runs when we edit a value in the table.
masterSelector(master1,master2,master3,master4);
var activeCell = e.range; // It returns the coordinate of the cell that we just edited.
var val = activeCell.getValue(); // Returns the value entered in the column we just edited.
var r = activeCell.getRow(); // returns the row number of the cell we edit.
var c = activeCell.getColumn(); // returns the column number of the cell we edit.
var wsName = activeCell.getSheet().getName();
if (wsName === masterWsName && c === firstLevelColumn && r > masterNumberOfHeaderRows) { // the if delimits the section sensitive to modification and action of the onEdit.
applyFirstLevelValidation(val,r);
} else if (wsName === masterWsName && c === secondLevelColumn && r > masterNumberOfHeaderRows){
applySecondLevelValidation(val,r);
}
} // end of onEdit
// addRow by checkboxes
function onEdit2(e) {
masterSelector(master1,master2,master3,master4);
//IF the cell that was edited was in column 4 = D and therefore a checkbox AND if the cell edited was checked (not unchecked):
if (e.range.columnStart === 4 && e.range.getValue() === true) {
var sheet = SpreadsheetApp.getActiveSheet(),
row = sheet.getActiveCell()
.getRow(),
//(active row, from column, numRows, numColumns)
rangeToCopy = sheet.getRange(row, 1, 1, 30);
sheet.insertRowAfter(row);
rangeToCopy.copyTo(sheet.getRange(row + 1, 1));
//Reset checked boxes in column 4
sheet.getRange(row,4,2,1).setValue(false);
}
}
Whole script is here, if needed.
A script cannot contain two functions with the same name. Rename your first onEdit function to onEdit1 (actually it will be better to assign a descriptive name) and the second function as onEdit2, then put them both in one function named onEdit and pass the parameter e to both of them:
function onEdit(e){
onEdit1(e);
onEdit2(e);
}
Related:
Two OnEdit functions not working together
Best Practices for Multiple OnEdit Functions
How to run multiple onEdit functions in the same google script (google sheets)?
Bracketing multiple onEdit functions
I tried to make onEdit function only respond to the specific range.
my onEdit function as bellow:
function onEdit(e){
var range = e.range;
var sheetName = e.source.getActiveSheet().getSheetName();
if (//trigger only when the cells from column A:H is edited
sheetName == "Email list" &&
range.rowStart >= 2 &&
range.columnStart >= 1 &&
range.columnStart <= 8
) {
sendMail()
}
}
function sendMail() {.... //the main function here
I have also deployed installable trigger using function onEdit. But I got TypeError: Cannot read property 'range' of undefined. Not sure which part is wrong or how should I define the variable within onEdit? Thank you.
Try following sample script:-
function onEdit(e)
{
const range = e.range
const sheet = range.getSheet();
const row = range.getRow();
const column = range.getColumn();
if (//trigger only when the cells from column A:H is edited
sheet.getName() == "Email list" &&
row >= 2 &&
column <= 8 // not taking 1 into consideration
) {
sendMail()
}
}
If you run the function directly, it will throw an error TypeError: Cannot read property 'range' of undefined, remove Edit installable trigger, as onEdit() is simple trigger
I believe your goal is as follows.
You want to run your onEdit by not only OnEdit simple trigger but also the standalone without the simple trigger.
In this case, how about the following modification?
Modified script:
function onEdit() { // If you want to use this function as the installable trigger, please rename the function name.
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveRange();
var sheetName = sheet.getSheetName();
if (//trigger only when the cells from column A:H is edited
sheetName == "Email list" &&
range.rowStart >= 2 &&
range.columnStart >= 1 &&
range.columnStart <= 8
) {
sendMail()
}
}
By this modification, you can directly run onEdit. And also, you can run onEdit by OnEdit trigger.
Note:
When you want to use your onEdit using the installable trigger, please rename the function name. About this, I thought that this thread might be useful.
Adding The data into another spreadsheet
This question already has an answer here:
How to allow onEdit function to affect protected cell in a Google Sheet?
(1 answer)
Closed 11 months ago.
I have a code:
function onEdit(e){
if (e.range.columnStart != 7 && e.range.columnStart != 8 || e.value <= 0) return;
let d = new Date();
if (e.range.columnStart == 7 && e.value == null){
e.range.offset(0,-2).setValue(null);}
else if (e.range.columnStart == 7 && e.value != null) {
e.range.offset(0,-2).setValue(d);}
else if (e.range.columnStart == 8 && e.value != null) {
e.range.offset(0,-3).setValue(d);}
}
function Lock(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var protection = sh.protect().setDescription('Lock');
var me = Session.getEffectiveUser();
protection.addEditor(me).setUnprotectedRanges(sh.getRange("I2:I").createTextFinder("^(?!Done).*$").matchEntireCell(true).useRegularExpression(true).findAll().map(r => r.offset(0, -3, 1, 3)));
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()){
protection.setDomainEdit(false);}
}
After running 2 functions. I edit in column 7 or column 8, will put the current date in the specified cell (column 5 in sheet), and will lock the range if I2:I has the value Done.
Everything works great with owner. But collaborators who are authorized to edit the spreadsheet cannot, onEdit(e) cannot run (error : You are trying to edit a protected cell or object. Please contact the spreadsheet owner to disable protection if you need to edit). Because function Lock() protected the sheet leaving only those cells where column I2:I is not done.
Is there any solution? Thanks!
I thought that in your situation, to use the simple trigger might be the reason of your issue. So, how about the following modification? In this modification, the function name is changed from onEdit to installedOnEdit, and the installable OnEdit trigger is installed to the renamed function.
From:
function onEdit(e){
To:
function installedOnEdit(e){
And also, please install the OnEdit trigger to the function installedOnEdit. And, please test it again.
Reference:
Installable Triggers
I want to create a script that will display the cell address of the active cell in A1, however, this is proving difficult because I can't even get the onSelectionChange example on the Google Apps Script guide to work. Whenever I run it, the error I get is TypeError: Cannot read property 'range' of undefined.
This is the code:
/**
* The event handler triggered when the selection changes in the spreadsheet.
* #param {Event} e The onSelectionChange event.
*/
function onSelectionChange(e) {
// Set background to red if a single empty cell is selected.
var range = e.range;
if(range.getNumRows() === 1
&& range.getNumColumns() === 1
&& range.getCell(1, 1).getValue() === "") {
range.setBackground("red");
}
}
About your error message of TypeError: Cannot read property 'range' of undefined, I thought that you might have directly run the function of onSelectionChange with the script editor. If it's so, such error occurs because the event object e is not given.
onSelectionChange is used as the simple trigger. In this case, when you want to retrieve the cell address of the active cell with onSelectionChange trigger, please select the cell on Google Spreadsheet. By this, the script is run by the onSelectionChange trigger.
Sample script:
For example, when the onSelectionChange trigger is run by selecting a cell, the sample script that the cell address is put to the cell as the A1Notation is as follows. When you use this script, please copy and paste the following script to the script editor of Spreadsheet and save it. And, please select a cell on the active Spreadsheet.
function onSelectionChange(e) {
var range = e.range;
range.setValue(range.getA1Notation());
}
Result:
When above script is used, the following result is obtained. You can see that in order to run the script, the cell is selected.
Note:
Even when you selected a cell, when the sample script is not run, please close the Spreadsheet and open the Spreadsheet again. In my environment, I confirmed that by this, the onSelectionChange trigger worked.
Reference:
onSelectionChange(e)
Added 1:
About the following your replying,
Thanks. This works and so did the red cell Google example. Although I did have to close the workbook and reopen it to get it to work. How can I set the range to a fixed cell so the active cell address only appears there?
When you want to run the script for only the specific range, how about the following sample script? From your replying, I used your script for this.
Sample script:
function onSelectionChange(e) {
var ranges = ["A2:B5", "D2:E5"]; // Please set the range you want to run the script.
var range = e.range;
var sheet = range.getSheet();
var check = ranges.some(r => {
var rng = sheet.getRange(r);
var rowStart = rng.getRow();
var rowEnd = rowStart + rng.getNumRows();
var colStart = rng.getColumn();
var colEnd = colStart + rng.getNumColumns();
return (range.rowStart >= rowStart && range.rowEnd < rowEnd && range.columnStart >= colStart && range.columnEnd < colEnd);
});
if (check) {
range.setBackground("red");
}
}
In this script, only when the cell in the range of var ranges = ["A2:B5", "D2:E5"] is selected, range.setBackground("red") is run. So please modify ["A2:B5", "D2:E5"] for your actual situation.
If you want to also check the sheet name, please modify above script as follows. In this case, when the cell in the ranges ["A2:B5", "D2:E5"] of the sheet ["Sheet2", "Sheet3"] is selected, range.setBackground("red") is run.
function onSelectionChange(e) {
var sheetNames = ["Sheet2", "Sheet3"]; // Please set the sheet names.
var ranges = ["A2:B5", "D2:E5"]; // Please set the range you want to run the script.
var range = e.range;
var sheet = range.getSheet();
if (!sheetNames.includes(sheet.getSheetName())) return;
var check = ranges.some(r => {
var rng = sheet.getRange(r);
var rowStart = rng.getRow();
var rowEnd = rowStart + rng.getNumRows();
var colStart = rng.getColumn();
var colEnd = colStart + rng.getNumColumns();
return (range.rowStart >= rowStart && range.rowEnd < rowEnd && range.columnStart >= colStart && range.columnEnd < colEnd);
});
if (check) {
range.setBackground("red");
}
}
Added 2:
About the following your replying,
No, sorry. I meant how can I make the active cell address appear in A1. If I click on cell G5, for example, 'G5' appears in A1.
In that case, how about the following sample script?
Sample script:
function onSelectionChange(e) {
var range = e.range;
range.getSheet().getRange("A1").setValue(range.getA1Notation());
}
I have written a script in google sheets that will change the time stamp in the selected cell anytime the entire spreadsheet is updated at all. However, I need the timestamp to only update when one single sheet(tab) is updated. Here is my current function:
function onEdit() {
var sheetActive = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("Board")
.getRange('A28')
.setValue(new Date());
}
The name of the sheet(tab) that I want to check for an update in is "Input" and the specific cell in the tab is A1 if that matters.
The onEdit trigger triggers whenever any sheet/tab is edited. It cannot be restricted to a single sheet. However, even if it is triggered, it is possible to make it do nothing with a simple if and testing the event object that is sent on each edit, which contains the circumstances of the edit made.
Sample:
/**
* #param {GoogleAppsScript.Events.SheetsOnEdit} param1
*/
function onEdit({ range: /*edited range*/ eRange }) {
const restrictCell = 'A1',
restrictToSheet = 'Input';
if (
eRange.getA1Notation() !== restrictCell ||
eRange.getSheet().getName() !== restrictToSheet
)
return;
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName('Board')
.getRange('A28')
.setValue(new Date());
}
This is what you are looking for :
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
if ( e.source.getActiveSheet().getName() === "Input" && (row==1 && col==1) ){
e.source.getSheetByName('Board').getRange('A28').setValue(new Date())
}
}