Learning scripts by trial and error. Please forgive probable ignorance in the question. I want a script to move a specific range (but not the whole row) in the active sheet to be positioned above another range in the active sheet. I want this move to take place upon edit and only when the text in column H is "C". The script I have so far runs with no errors but does not affect any change. Additionally, I would like this same thing to happen not only for row 4 but for rows 4-18. I was simply going to copy successful lines multiple times and update range for each, but I am sure there is a better way?
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var rangetoWatch = ("F4:I4");
var columnNumberToWatch = 8;
var valueToWatch = "C";
if (sheet.getName() == sheet && sheet.getRange() == range.getColumn() == columnNumberToWatch && rangetoWatch.getValue() == valueToWatch) {
sheet.getRange("F20:I").moveTo(sheet.getRange("F21"));
sheet.getRange("F4:I4").moveTo(sheet.getRange("F20:I20"));
}
}
in case anyone stumbles across this thread in the future... i finally figured out what I was trying to accomplish. a sample script is below.
function movedown(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var row = range.getRow();
var mini = sheet.getRange(row, 1, 1, 3);
var columnNumberToWatch = 3;
var valueToWatch = "C";
if (range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
sheet.getRange("A15:C").moveTo(sheet.getRange("A16"));
sheet.getRange(row, 1, 1, 3).copyTo(sheet.getRange("A15:C15"));
sheet.getRange(row, 1, 1, 3).clear({contentsOnly:true});
}
}
I think this is what you want. But I did not find your explanation to be very clear.
function onEdit(e) {
var sheet=e.range.getSheet();
//next line not required if you want it to happen on all sheets
if(sheet.getName()!='SomeSheetName'){return;}//keep the process from only happening on one sheet
if(e.range.rowStart>=4 && e.range.rowStart<=18 && e.range.columnStart==8 && e.value=='C') {
sheet.getRange(20,6,sheet.getLastRow(),4).moveTo(sheet.getRange(21,6));
sheet.getRange(e.range.rowStart,6,1,4).moveTo(sheet.getRange(20,6,1,4));
}
}
Related
For starters, I am a complete beginner at using Apps Scripts for Google Sheets at my new workplace, and we do not have an IT department who can help us create this file. I am trying to create a shared file that can be accessed by our client, our service technicians, and our main office simultaneously, so I opted to create a Google Sheet.
I am hoping to automate this process to prevent users (except myself) from needing to manually edit, move and sort data across multiple sheets that might cause the file to break or become inconsistent. For this to work, I need users to only be able to create entries in our 'main' worksheet and only view the other sheets. From here, I'd like to automate the file to move rows to specific sheets named after each unit when it's marked "DONE", and also organize each unit's sheet by the date column. Our intention is for these sheets to provide us with a running history of all the work that has been done each unit.
NOTE: I have 54 units and counting and I currently will have to copy & paste the code multiple times and edit each one to match the unit numbers. I currently have a one unit set-up, but I think there's something wrong with the code or the triggers I have set-up as it does not automatically sort the destination sheet. Either way, I think there has to be a simpler way to do this.
Any advice would be appreciated!
Here's the code that I've used thus far:
function trailer27() {
// moves a row from a sheet to another when a magic value is entered in a column
// adjust the following variables to fit your needs
// see https://productforums.google.com/d/topic/docs/ehoCZjFPBao/discussion
var sheetNameToWatch = "WORKSHEET";
var columnNumberToWatch = 6;2 // column A = 1, B = 2, etc.
var valueToWatch = "Yes";"27"
var sheetNameToMoveTheRowTo = "27"
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.deleteRow(range.getRow());
SpreadsheetApp.flush()
}
}
function Sort27() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("27")
var range = sheet.getRange("A3:F1000");
// Sorts by the values in column 1 (J)
range.sort({column: 1, descending: false});
}
function SortWorksheet(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("WORKSHEET")
var range = sheet.getRange("A3:F1000");
// Sorts by the values in column 10 (J)
range.sort({column: 1, descending: false});
}
function undoMove() {
// moves a row from a sheet to another when a magic value is entered in a column
// adjust the following variables to fit your needs
// see https://productforums.google.com/d/topic/docs/ehoCZjFPBao/discussion
var sheetNameToWatch = "27"
var columnNumberToWatch = 6; // column A = 1, B = 2, etc.
var valueToWatch = "CALLED"; "EMAIL"
var sheetNameToMoveTheRowTo = "WORKSHEET";
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.deleteRow(range.getRow());
SpreadsheetApp.flush()
}
}
If this is meant to be an onEdit function it's worth using the event object even considering the difficulty in debugging
function trailer27(e) {
const sheet = e.range.getSheet();
var sheetNameToWatch = "WORKSHEET";
var columnNumberToWatch = 6; 2 // column A = 1, B = 2, etc.
var valueToWatch = "Yes"; "27"
var sheetNameToMoveTheRowTo = "27"
if (sheet.getName() == sheetNameToWatch && e.range.columnStart == columnNumberToWatch && e.value == valueToWatch) {
var targetSheet = e.source.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(e.range.rowStart, 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(e.range.rowStart);
SpreadsheetApp.flush();
}
}
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);
}
}
Obviously I have a small error as the code used copies the entire page, not just the row.
What I am trying to achieve is whenever "Green" is entered in Column 4 on Sheet "Jobs", the script copies that row to the next empty row on Sheet "Fleet"
I was also wondering if there is a way to possibly shade the copied row as a confirmation it has been copied to the "Fleet Sheet"
Here is the code so far:
function onEdit()
{
var sheetNameToWatch = "Jobs";
var columnNumberToWatch = 4;
var valueToWatch = "Green";
var sheetNameToCopyTheRowTo = "Fleet";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() ==
columnNumberToWatch && range.getValue() == valueToWatch)
{
var targetSheet = ss.getSheetByName(sheetNameToCopyTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(2, 1, sheet.getLastRow(),
sheet.getLastColumn()).copyTo(targetRange);
}
}
Here is the link to an open copy of the spreadsheet (no important data so feel free to edit):
https://docs.google.com/spreadsheets/d/138PBXEsKdhhxkKNTCGaFaWgrOTQcnN3tPWHO8pp7GMg/edit#gid=610845771
I am trying to move a row to the next tab once "Live" has been selected from a drop down menu. I just want the values and for the formatting to be disregarded.
I have had this working in the past on edit, but a recently it has decided that it it wont work unless i have a button to press on the sheet and it has also started dragging through all the data validation and conditional formatting with it. I haven't changed anything in the script, and don't think any of my colleagues have either.
Any help would be much appreciated.
function Projects(e) {
// moves whole row when "Live" is selected from drop down menu
var sheetNameToWatch = "Projects";
var columnNumberToWatch = 8;
var valueToWatch = "Live";
var sheetNameToMoveTheRowTo = "Status Tracker";
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.deleteRow(range.getRow());
}
}
Two things:
Delete the trigger and re-install it.
Instead of using moveTo(), which includes formatting, use copyTo() and include the contentsOnly option.
The modified code below should work for you. Note that I've also made some changes so that it's taking full advantage of the event object being passed to it.
function Projects(e) {
// moves whole row when "Live" is selected from drop down menu
var sheetNameToWatch = "Projects";
var columnNumberToWatch = 8;
var valueToWatch = "Live";
var sheetNameToMoveTheRowTo = "Status Tracker";
var ss = e.source; // use the event object to get the spreadsheet
var range = e.range; // use the event object to get the edited cell
var sheet = e.range.getSheet(); // use the event object to the get the sheet
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()).copyTo(targetRange, {contentsOnly:true});
sheet.deleteRow(range.getRow());
}
I want to have a script execute only if all required cells contain information.
The above sheet shows how the layout is. The rows that need to be populated for the script to start are columns B to G
An extra feature that I would also like but is not required is if the user does not fill in all the cells required it will highlight them in red and delete the values in columns H & I of the active row in question.
Below is the script that executes when column H has the value "Completed"
function moveComplete() {
Utilities.sleep(200);
var sheetNameToWatch = "REQUEST";
var columnNumberToWatch = 9;
var valueToWatch = "COMPLETED";
var sheetNameToMoveTheRowTo = "ARCHIVE";
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, 2);
sheet.getRange(range.getRow(), 2, 1, sheet.getLastColumn()).setDataValidation(null).moveTo(targetRange);
sheet.deleteRow(range.getRow());
var lastrow = sheet.getLastRow();
sheet.insertRows(lastrow, 1);
}
}
You should trigger a checking (depending on what value you need) on all the cells that correspond as a required value with onEdit(). Afterwards, simply trigger your moveComplete() function to populate the rest of the other cells you need.
This Google Docs Help Forum post might give you an idea on how to do it. Just modify some of the code snippets that are already provided there. Other helpful docs:
Google AppScipt Triggers
Google AppScript Event Objects