Google Sheets two onEdits, second onEdit conflicts with first [duplicate] - google-apps-script

This question already has an answer here:
Merging or Combining two onEdit trigger functions
(1 answer)
Closed 1 year ago.
I'm working in Google sheets trying to set up two onEdit scripts, one to work right after the other. I'm not really a coder but can at least somewhat read coding and for the most part, figured out what and where to change things to make scripts work for my spreadsheet. I've looked all over StackOverflow and Google's help forum but nothing exactly has helped with me with the issue I'm facing.
Here is what I'm trying to do. Column 12 (L) is a status column with the options; In progress, No Resolution, Resolved.
When anything gets flipped to Resolved, I'd like it to move to the bottom of the spreadsheet and then that bottom row gets highlighted.
Here are the two scripts I'm working with, on their own they do what I want but together the second script runs first highlighting the row, and then it moves to the bottom. Also for some reason when the second script is active there is a 50-50 that when the entry is moved to the bottom is moves up one row.
First script:
function onEdit(e){
// assumes source data in sheet named Problems
// target sheet of move to named Problems, Problems
// test column with yes/no is col 12 or L
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Problems" && r.getColumn() == 12 && r.getValue() ==
"Resolved") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Problems");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
Second script:
function onEdit2(e) {
if (e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
if (r.getRow() != 1 && ss.getName() == "Problems") {
status = ss.getRange(r.getRow(), 12).getValue();
rowRange = ss.getRange(r.getRow(),1,1, 12);
if (status == 'Resolved') {
rowRange.setBackgroundColor("#99ccff");
}
}else if (status == '') {
rowRange.setFontColor("#000000");
}
}
}
I've set the onEdit2 to a trigger but that hasn't worked :(
Any help is appreciated and please let me know if any more information is needed.

Try this function. It'll move the Resolved row to bottom then highlight it.
function onEdit(event) {
var sheet = event.source.getActiveSheet();
var range = event.source.getActiveRange();
// move
if (sheet.getName() == 'Problems' && range.getColumn() == 12 && range.getValue() == 'Resolved') {
var row = range.getRow();
var numColumns = sheet.getLastColumn();
var tRange = sheet.getRange(sheet.getLastRow() + 1, 1, 1, numColumns);
tRange.setValues(sheet.getRange(row, 1, 1, numColumns).getValues());
tRange.setBackgroundColor('#99ccff');
sheet.deleteRow(row);
}
}

The onEdit(e) function is a reserved function by Google AppScript just like the other trigger functions (onOpen(), onChange, ...). Calling it onEdit2(e) will not work as it is not recognized as a trigger function.
Simply change the name to onEdit() so that Google AppScript can trigger it.
Let me know if that works for you

Related

onedit script in google sheet works for only one function

I have 2 scripts in the same project but it seems that only one is working, not specific but depending on the time I add the script, it is like the last script Im adding disabling the other.
these are the 2 scripts (I copied from google forum and updated according to my needs):
adding an auto time stamp to a cell when specified range is not empty:
function onEdit(event) {
var sp = SpreadsheetApp.getActiveSheet();
var c = sp.getActiveCell();
if (c.getColumn() < 9 && sp.getName()=='QUE') {
var celladdresp ='I'+ c.getRowIndex()
sp.getRange(celladdresp).setValue(new Date()).setNumberFormat("dd/mm/yy hh:mm");
}
};
copy a row to another sheet on the same file if checkbox is checked (=true):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "QUE" && r.getColumn() == 12 && r.getValue() == true) { var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("QUE2");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns-2).copyTo(target);
}
};
Your help understanding why they dont work together will be appreciated.
*BTW I tried to Enable/Disable new apps scriptspowered by chrome v8 but did not helped
Answer:
You can only have one onEdit(event) function per script. If you wish both functions to run on edit, you need to combine them.
More Information
It's programming 101 that all functions and variables have to have unique names - otherwise your code isn't going to know which function or variable you're referring to. The uniqueness is important as you're defining exactly what you want.
In this case, as you have two onEdit(event) functions, when the sheet is edited your script is only calling one of these functions. This makes sense - it has no reason to continue looking for more doGet()s if it's already found and executed one.
Merging Functions:
When merging, it's important not to replicate code that is unneccesary. Reducing the number of calls so you only do exactly what you need to is important for efficient-running code:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
var r = event.source.getActiveRange();
var c = sheet.getActiveCell();
if (c.getColumn() < 9 && sheet.getName() == 'QUE') {
var celladdresp = 'I' + c.getRowIndex()
sheet.getRange(celladdresp).setValue(new Date()).setNumberFormat("dd/mm/yy hh:mm");
}
if(sheet.getName() == "QUE" && r.getColumn() == 12 && r.getValue() == true) { var row = r.getRow();
var numColumns = sheet.getLastColumn();
var targetSheet = ss.getSheetByName("QUE2");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(row, 1, 1, numColumns-2).copyTo(target);
}
}

Google Sheets Script Help Request: Copy check boxed rows from multiple sheets to new sheet

Full disclosure: I have zero programming experience, but I'm a quick study.
I am trying to be able to copy individual rows from a number of different sheets to be copied to one specific sheet. I spent some time looking at previous questions/answers on this (great) site, and I was able to piece together a script that seems to do PART of what I'm looking for.
I can see where in the script I could/should change to get the functionality I'm looking for -- BUT I don't know what to put in the code to actually do what I'm hoping to do. I come to this community humbly asking for help/guidance.
Here's the script that I pieced together and a link to the example I've been working with:
function onEdit(event) {
// assumes source data in sheet named ABC
// target sheet of copy to named Interdisciplinary
// getColumn with check-boxes is currently set to colu 15 or O
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "ABC" && r.getColumn() == 15 && r.getValue() == true) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Interdisciplinary");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
} else if(s.getName() == "Interdisciplinary" && r.getColumn() == 4 && r.getValue() == false) {
}
}
I know that I'm identifying a specific sheet to pull data from (ABC), what might I put there to pull from any sheet where a checkbox has been clicked?
I also know that I'm having the rows copied to a row that is some defined place away from the LastRow. What might I be able to put there to have the row copied either a row w/in my semester headings OR to have the copied to the top of the new sheet?
Finally, I'd truly appreciate any other comments, feedback, guidance that the community might have for my request.
Thanks much!
Kd
Your code works. The problem is that the code in your spreadsheet is looking at column 21, not column 15.
Also, I suggest that you review the properties available to you in the event object. You should use them instead of the first three declarations you wrote. You can see the change in my version below.
function onEdit(event) {
var sheets = ["ABC", "DEF", "GHI", "JKL", "MNO"]; // Sheet names that will trigger execution. Case-sensitive.
// target sheet of copy to named Interdisciplinary
// getColumn with check-boxes is currently set to colu 15 or O
var ss = event.source;
var s = event.range.getSheet();
var r = event.range;
if (sheets.indexOf(s.getName()) != -1 && r.getColumn() == 15 && r.getValue() == true) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Interdisciplinary");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
} else if(s.getName() == "Interdisciplinary" && r.getColumn() == 4 && r.getValue() == false) {
}
}
EDIT: I've modified the code to show you how to allow triggering from multiple sheets.

How can I make my onEdit code recognize pasted data on multiple cells?

I copied a code from https://www.seerinteractive.com/blog/google-sheets-scripts/ to move rows from one tab to another. I modified the code to trigger it whenever a cell in the specified column was edited. It worked on both manual edit and copy pasted data, but when I tried copy pasting the data on multiple cells in the specified column, it only moves the first cell in the selection and the rest of the cells below doesn't move. Also when I edit the cell too fast, it sometimes doesn't move the row.
I tried using the onChange trigger but I cannot figure out how to make it work.
function onEdit() {
var sheetNameToWatch = "raw";
var columnNumberToWatch = 16;
// column A = 1, B = 2, etc…
var valueToWatch = "1";
var sheetNameToMoveTheRowTo = "data prep";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.clearContents(range.getRow());
}
The question has two parts
Regarding getting all the values of a range, use getValues instead of getValue. This will return an array of arrays (2D array).
Regarding the onEdit trigger not being triggered all the time, this is an known limitation of onEdit. It's already reported on the issue tracker an on some questions here.
Related
Failure of calling Google App Script onEdit function many times in a second

Apps Script script in Google Sheets moving the wrong row with two onEdit triggers

I am using 2 functions in a tracker that I have. 1 function is for sorting column C by date (earliest first) automatically when a cell in that column is edited. If the word 'done' or 'void' is typed into that cell then the entire row is copied onto the next sheet.
However my issue is that when I type 'done' or 'void' into this cell, Google sheets is sorting the list and also processing the move function and thus moving the wrong row (the resulting row number, after the sort). How can i fix or improve the code.
function movedonevoid(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
var value = r.getValue();
if(s.getName() == "tracker" && r.getColumn() == 3 && (value=="done" || value=="void" )) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("tracker2");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
and
function sorttracker(event){
var sheet = event.source.getActiveSheet();
if(sheet.getName() == 'tracker'){
var editedCell = sheet.getActiveCell();
var columnToSortBy = 3;
var tableRange = "A2:D"; // What to sort.
if(editedCell.getColumn() == columnToSortBy) {
var range = sheet.getRange(tableRange);
range.sort( { column : columnToSortBy, ascending: true } );
}
}
}
I've inserted the above 2 bits of code as 2 different scripts and then used project triggers for both 'on edit'. Not sure if that is the best approach?
As you already noticed, having two different functions acting over the same range and being called by two different onEdit triggers isn't a good idea.
Instead of using two onEdit triggers, use only one to call an orchestral conductor function that will call the original two. The orchestral conductor function could be something like the following:
function onEdit(e) {
movedonevoid(e);
sorttracker(e);
}

Review of personal code

I found this code and implemented it into my spreadsheet. My problem is that the code overwrites some data validation I had in my empty list. I wish to keep that drop down menu since I want the users to have it as easy as possible. I thought I could add the lines below (see text between **)
function onEdit(event) {
// assumes source data in sheet named Masterlist
// target sheet of move to named Actionlist
// test column with yes/no is col 13 or M;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Masterliste"
&& r.getColumn() == 13 && r.getValue() == "Ja") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Actionlist");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
// **
var cellrange = SpreadsheetApp.getActive().getRange(target);
var range = SpreadsheetApp.getSheetByName("Dropdown").getRange('A16:B18'); //This is the range for the dropdown I want to hand over.
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(range).build();
cell.setDataValidation(rule); //Include a data validation menu in each line automatically
// **
s.getRange(row, 1, 1, numColumns).copyTo(target); //This executes the copy order with the data provided before
}
}
I know this might be easy for some of you but I have just started with google 4 months ago and it's driving me crazy. I am familiar to excel and VBA, but not to Java at all.
Yes I did already do the codeacademy courses. They really didn't help me a lot. Sorry for my tone I am getting really annoyed by this. Thanks for your help. Enjoy the weekend!
You need to add an option to copyTo. Here is what that looks like:
s.getRange(row, 1, 1, numColumns).copyTo(target, {contentsOnly:true});
Alternatively you could use: copyValuesToRange(sheet, column, columnEnd, row, rowEnd)
https://developers.google.com/apps-script/reference/spreadsheet/range#copyTo(Range,Object)