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
Related
In my Google Sheets, I'm trying to select cell A1 after my onSelectionChange Google Apps script executes, but even though the rest of the script executes, the selection doesn't change at the end. Selecting cell A1 is supposed to be done by the last three lines of code below. These three lines of code work fine in another script for another sheet, but for some reason they won't work in this even simpler script.
function onSelectionChange(e) {
// Insert date in a new cell, shifting existing cells down and then counting nonblank cells.
console.log("Start");
var range = e.range;
if(range.getColumn() >= 2
&& range.getColumn() <= 3
&& range.getNumRows() === 1
&& range.getRow() === 2)
{ var d = new Date();
range.offset(2,0).insertCells(SpreadsheetApp.Dimension.ROWS);
range.offset(2,0).setValue(d);
range.offset(1,0).setFormulaR1C1("counta(R[1]C[0]:C[0])");
var sheet = range.getSheet();
var cell = sheet.getRange("A1");
sheet.setCurrentCell(cell);
}
}
Try Using activate() Instead
activate() sets the specified range in getRange("<Range>") as the active range. For your script, you simply need to modify the last line to select cell A1 after the process triggered is done. It should look like this:
function onSelectionChange(e) {
// Insert date in a new cell, shifting existing cells down and then counting nonblank cells.
console.log("Start");
var range = e.range;
if(range.getColumn() >= 2
&& range.getColumn() <= 3
&& range.getNumRows() === 1
&& range.getRow() === 2)
{ var d = new Date();
range.offset(2,0).insertCells(SpreadsheetApp.Dimension.ROWS);
range.offset(2,0).setValue(d);
range.offset(1,0).setFormulaR1C1("counta(R[1]C[0]:C[0])");
var sheet = range.getSheet();
var cell = sheet.getRange("A1");
cell.activate(); //change done in this line.
}
}
Output
Reference
activate()
I'll start by saying that I'm a complete novice but I spent a few hours manipulating a bit of code I found online to fit a sheet I'm designing. I'm attempting to create a script that will generate a dynamic dropdown to the right of a cell when a value is selected from an existing dropdown.
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Lists")
var r = event.range;
if(r.getColumn() == 3 && r.getRow() > 1 && ss.getName() == "Main"){
r.offset(0, 1).clearContent().clearDataValidations();
var types = datass.getRange(1, 1, 1, datass.getLastColumn()).getValues();
var typeIndex = types[0].indexOf(r.getValue()) + 1;
if(typeIndex != 0) {
var validationRange = datass.getRange(2, typeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
r.offset(0, 1).setDataValidation(validationRule);
}
}
}
Here's my process so far:
I created the initial script with var r = ss.getActiveCell(), which worked for a single cell at a time, but I need it to work when multiple rows are pasted. Version 1
I edited to var r = event.range, which successfully applied the script to all rows that were pasted. However, the script only generated the list for the top cell that I pasted and created that same list for all pasted cells. Version 2
What I need is for onEdit to essentially re-trigger for each row when data is pasted in. Goal Version
Rather than re-triggering onEdit make it to be able to handle both cases. For this, you could take advantage of Range.getRows(), Range.getColumns() as well of edit event object properties like (in this answer e is the event object):
e.range.rowStart
e.range.rowEnd
e.range.columnStart
e.range.columnEnd
If a single cell was edited, rowStart and rowEnd will have the same value, the same for columnStart and columnEnd.
i.e. you might replace
r.offset(0, 1).clearContent().clearDataValidations();
by (remember, I'm using e instead of event for the event object)
r.offset(0, 1, e.range.getRows()).clearContent().clearDataValidations();
Related
Google script onEdit in all pasted cells
How to customize onEdit() script to work on all rows modified when a list of values is pasted from the clipboard?
First of all, I ask you to excuse me if I make some language-mistake (I'm Italian!).
I'm trying to write a script for a Google Sheet that can help me to track the number of changes of a column. I would like a counter that grows everytime a value of a cell changes. Ex:
-Column A: the cell A3 changes from "2020" to "2021"
-Column B: the cell B3 changes from 0 to 1 (o from 2 to 3, a simple +1 on the value).
I wrote this code but I cannot understand where is the error.
function onEdit(e) {
incrementCounter_(e);
}
function incrementCounter_(e) {
var stw = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Foglio2");
var c1 = stw.getRange(2, 1);
var c2 = stw.getRange(2, 2);
if (!e || !e.range) {
return;
}
var sheet = e.range.getSheet();
for (var i=2; i<=6; i++){
if (sheet.getName() === stw && e.range.getA1Notation() === stw.getrange().getvalue(i,1)) {
var cell = stw.getrange().getvalue(i,2);
cell.setValue((Number(cell.getValue()) || 0) + 1);
}
}
}
Thanks for the help!
There is no need to use two functions for this.
Code
// Copyright 2020 Google LLC.
// SPDX-License-Identifier: Apache-2.0
function onEdit(e) {
var sheet = e.range.getSheet();
var sheetName = sheet.getName();
if (sheetName == "Foglio2" && e.range.getColumn() == 1) {
var row = e.range.getRow();
var val = sheet.getRange(row, 2).getValue();
sheet.getRange(row, 2).setValue(val + 1);
}
}
Explanation
What you want can be achieved by using the onEdit(e) trigger. The above function makes use of the e event object and checks where exactly the edit is being made. As it can be seen, the for loop is not needed in this situation as in order to get the column and row needed the getColumn() and getRow() methods have been used.
In this situation, the script checks if the sheet in which the edit has been made is Foglio2 and if an edit has been made on the A column. If the condition checks, it increments the corresponding value from the B column.
Note
Please note that getValue(value1, value2) is not a valid method and if you want to get the value for that specific range, you must pass the two parameters to the getRange() method.
Reference
Apps Script Event Objects;
Apps Script Sheet Class;
Apps Script Range Class - getValue().
Do you mean this?
function onEdit(e) {
if (e.range.getA1Notation() === 'A3') {
var range = SpreadsheetApp.getActiveSheet().getRange('B3');
var value = range.getValue();
value++;
range.setValue(value);
}
}
I have this script to hide those rows which contains the word - 'Matured' (in column F)
function onEdit(e) {
var sheet = e.source.getActiveSheet();
var r = e.source.getActiveRange();
if (sheet.getName() == "Follow-ups LAPL" && r.getColumnIndex() == 6 && r.getValue() == "Matured")
sheet.hideRows(r.getRowIndex(),1);
The problem is - the script does the job of hiding the row only when the 'Matured' is entered MANUALLY (in column F), but it does not work if the same is brought in through importrange (in same column F).
Is it by design, or is there any workaround?
Thanks for help!
It is by design. You may trigger the onchange event rather than the onEdit event for your use case or you may trigger both. See if onChange works in both cases, if so you may trigger only that. If it doesn't then you may trigger both events at the same time.
You may trigger multiple events on the same function by going to the Current Project's trigger as shown below:
You can create your own function and trigger every minute. But make sure in master spreadsheet (Spreadsheet id which you included in importrange) you delete empty cells or else in below loop sheet.getLastRow() will count empty cells too which will result in unnecessary iteration.
function onModified() {
var ss = SpreadsheetApp.openById('SPREADSHEET ID');
var sheet = ss.getSheetByName("Follow-ups LAPL");
var getData = sheet.getRange(1, 6, sheet.getLastRow(), 1).getValues();
Logger.log(getData.length);
for (var i = 0; i < getData.length; i++) {
if (getData[i][0] == "Matured") {
sheet.hideRows(i+1,1);
} else {
sheet.showRows(i+1, 1);
}
}
}
I'm completely new to Google script writing, but I've used various posts here to piece together what I need: something that will add a time stamp to a row when a certain column changes. Here's what I'm currently using:
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "test" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 16 ) { //checks the column
var nextCell = r.offset(0, 1);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
}
}
This works perfectly when I manually change the data; however, the column that the script is monitoring pulls data from another sheet and this fails to fire the trigger/script. How can I get around this so that cells with formulas (that reference other sheets) will still fire my script?
Any help is greatly appreciated. Thanks!
The onEdit trigger works only when an actual user edits the spreadsheet. Depends of your use case, but you can be use a Time-driven trigger and set it in a recurring interval and with a function monitor the column for changes, here's an example:
function monitorColumn() {
// Add the trigger from the Resources menu in the Script Editor
// Script Editor > Resources > Current oroject's triggers > Add trigger
// [monitorColumn] - [Time-driven] - [Hour timer] - [Every hour]
var s = SpreadsheetApp.getActiveSpreadsheet();
var ss = s.getSheetByName("test"); // Get the sheet by name
// Get the values of the columns P & Q with getRange(row, column, numRows, numColumns)
var columnValues = ss.getRange(1, 16, ss.getLastRow(), 2).getValues();
// Loop through the values
for (var i = 0; i < columnValues.length; i++) {
// If cell in column P is empty and cell in column Q is not empty set todays date
if(columnValues[i][0] != "" && columnValues[i][1] == ""){
// While a range index starts at 1, 1, the JavaScript array will be indexed from [0][0].
ss.getRange(i+1,17).setValue(new Date());
}
}
}