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
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();
}
}
This is my first Google Script and I am coming from a VBA background so I have likely missed something obvious. I am attempting to copy from one sheet to another, some that is quite simple in VBA, but I am struggling with it and I dont understand what I am missing
The below code I would have though would copy a range in one sheet to another sheet. Not the whole range, just a section of it and only 1 row per an OnEdit()
I checked the ranges I am wanting to copy from and copy to using targetSheet.getRange(targetSheet.get1stNonEmptyRowFromBottom(1) + 1, 1,1,numColumns-1).activate(); & sheet.getRange(row, 1, 1, numColumns-1).activate(); and it selects the range I would expect
Currently the execution doesn't show any fails either
function onEdit(e) {
//This is sheet we will be copied to
const VALUE = ["LEAD","LANDSCAPE"];
//This is the column for the check box
const COLUMN_NUMBER = 25
//The main sheet that is being copied from
const MAIN_SHEET = 'Form Responses 1'
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var lead_or_landscape = sheet.getRange(row,20).getValue();
//This is so we dont run this by mistake on another cell edit or sheet
if((COLUMN_NUMBER == cell.getColumn() && MAIN_SHEET == sheet.getName && cell.isChecked() == true)
&& (lead_or_landscape == VALUE[0] || lead_or_landscape == VALUE[1])){
//copies row from current sheet to the specificed sheet (Lead or landscape)
var numColumns = sheet.getLastColumn();
var targetSheet = spreadsheet.getSheetByName(lead_or_landscape);
var target = targetSheet.getRange(targetSheet.get1stNonEmptyRowFromBottom(1) + 1, 1,1,numColumns-1);
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target());
}
}
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
You've to use parentheses in sheet.getName() and not use them in copyTo(target())
And you can use sheet.appendRow() method instead of copyTo(), that is easier.
function onEdit(e) {
//This is sheet we will be copied to
const sheets = ["LEAD","LANDSCAPE"];
//This is the column for the check box
const colNumber = 25;
//The main sheet that is being copied from
const mainSheet = 'Form Responses 1';
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var leadOrLandscape = sheet.getRange(row,20).getValue();
//This is so we dont run this by mistake on another cell edit or sheet
if(colNumber == cell.getColumn()
&& mainSheet == sheet.getName()
&& cell.isChecked() == true
&& sheets.includes(leadOrLandscape)){
//copies row from current sheet to the specificed sheet (Lead or landscape)
var numColumns = sheet.getLastColumn();
var targetSheet = spreadsheet.getSheetByName(leadOrLandscape);
targetSheet.appendRow(sheet.getRange(row, 1, 1, numColumns-1).getValues()[0])
}
}
I just took a quick look at your code, are you sure about this line?
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target());
it shouldn't rather be
sheet.getRange(row, 1, 1, numColumns-1).copyTo(target);
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));
}
}
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