I have a script to move a Google Sheets row from one sheet to another based on the value of a cell. What I'm now trying to accomplish is cherry picking column placement.
For example 'Client' in Column one gets moved from Leads to Opportunities in the corresponding column one, and 'Client Phone' in Column Two gets moved from leads to column five in opportunities, and 'Source' in column three just gets skipped all together, then repeat with following columns.
Any thoughts on how to achieve this? Thanks in advance!
Here is the code I have for moving rows.
function onEdit() {
// moves a row from a sheet to another when a magic value is entered in a column
var sheetNameToWatch = "Leads";
var columnNumberToWatch = 9;
var valueToWatch = "Opportunity";
var sheetNameToMoveTheRowTo = "Opportunities";
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());
}
}
An "object literal" can be used to make user settings that will determine the source and destination.
Example:
function onEdit() {
var mySettings,thisSheet;//Define variables without assigning a value
// USER INPUT
mySettings = {//make settings here
"targetSheetOne":{//First sheet to get data
"columnToColumnMap":{//source column to be put in target column
"column1":"column5",//source column1 will be copied to target column5
"column2":"column2",
"column3":"column3"
}
}
}
// END OF USER INPUT
for (key1 in mySettings) {//Loop through all target sheets in settings
thisSheet = SpreadsheetApp.getSheetByName(key1);
innerObject = mySettings[key1];
for (key2 in innerObject) {
//Write column data to correct column
}
}
}
Related
https://docs.google.com/spreadsheets/d/1wAxZROq-HqGSZIeBnOShiLP1x-maCpVhvfr6MKixVZE/edit#gid=1767460404
I am attempting to grab the data in a data range on a data sheet, then loop over that data, match the row values in Column C to the row values in a different (tracker) sheet also located in Column C, and for the matched data, copy the whole row in data sheet to the bottom of the data sheet.
All of this is supposed to be triggered when I enter "Open" in a set field in the status tracker.
What I have done so far (hopefully) is to locate the values to match in the data sheet but I am unsure as to how to use the .copyto function correctly now such that it copys the data to the end of the loop. My code so far: (without .copy.
function grabmyRequestID(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var ss2 = ss.getSheetByName("Status Tracker")
var searchforrange = ss2.getRange("C:C")
var searchfor = searchforrange.getValues()
Logger.log("Request ID: " +searchfor)
return searchfor
}
function findDuplicates(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
var ss2 = ss.getSheetByName("Status Tracker")
var ss3= ss.getSheetByName("All Output")
var sheetNametoWatch = "Status Tracker"
var columntoWatch = 4
var valuetoWatch = "Open"
var searchfor = grabmyRequestID()
if (sheet.getName() == sheetNametoWatch && range.getColumn()
== columntoWatch && range.getValue() == valuetoWatch){
var data = ss3.getRange("C:C").getValues()
for (i=0; i<data.length; i++){
if (data[i] == searchfor && searchfor !=""){
Logger.log('found it')
}
}
}
}
As you can see, I am running two functions, grabmyRequestID, which grabs the id from the tracking sheet and findduplicates, which matches it with the ids from the data sheet.
I now just want it to copy the whole row where it found the matched column and copy that row to the end of the data sheet. I have tried a few ways but I never actually get any output. I am pretty new to this so I hope somebody can help me out.
I am also not sure entirely sure if my trigger works for this loop.
Any help would be appreciated.
I've spent hours trying to get this to work so any help is much appreciated I've got the code below copying from my main sheet to logs. However the code I'm trying to alter looks to column 10 for the sheet name. I'd like this just to default to the sheet logs any idea what needs changing to make this happen? Thanks in advance
function onEdit(e) {
// see Sheet event objects docs
// https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events
var ss = e.source;
var s = ss.getActiveSheet();
var r = e.range;
// to let you modify where the action and move columns are in the form responses sheet
var actionCol = 9;
var nameCol = 10;
var target = SpreadsheetApp.openById('18L5-RGHBx41sMtvC1-7AoVCo6y3imvtELQFjkhPXtoY')
var targetsheet = target.getSheetByName('logs');
// Get the row and column of the active cell.
var rowIndex = r.getRowIndex();
var colIndex = r.getColumnIndex();
// Get the number of columns in the active sheet.
// -1 to drop our action/status column
var colNumber = s.getLastColumn()-1;
// if our action/status col is changed to yes do stuff
if (e.value == "Yes" && colIndex == actionCol) {
// get our target sheet name - in this example we are using the priority column
var targetSheet = s.getRange(rowIndex, nameCol).getValue();
// if the sheet exists do more stuff
if (ss.getSheetByName(targetSheet)) {
// set our target sheet and target range
var targetSheet = ss.getSheetByName(targetSheet);
var targetRange = targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, colNumber);
// get our source range/row
var sourceRange = s.getRange(rowIndex, 1, 1, colNumber);
// new sheets says: 'Cannot cut from form data. Use copy instead.'
sourceRange.copyTo(targetRange);
// ..but we can still delete the row after
r.setValue("Logged")
// or you might want to keep but note move e.g. r.setValue("moved");
}
}
}
It looks like you are trying to get a sheet by it's name.
The following code will return the sheet named Logs.
var targetSheet = SpreadsheetApp.getActive().getSheetByName('Logs');
Google Apps Script Documentation: getSheetByName(name)
I am trying to loop through rows within a spreadsheet and identify if a particular row has the key word "hello" and move that entire row into a new spreadsheet.
I have attempted the following code. The code works for the first row but doesn't loop through and stops after the first row. Expanding the range selection to "C1:E32" does not help.
function Edit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activatedSheetName = ss.getActiveSheet().getName();
var ActiveSheet = ss.getSheetByName("ActiveSheet"); // source sheet
var MoveDatatoThisSheet = ss.getSheetByName("MoveDatatoThisSheet"); // target sheet
var re = new RegExp(/(Hello)/i);
var startRow = 1;
var endRow = ss.getLastRow();
var getRange = ss.getDataRange();
var getRow = getRange.getRow();
for (var ree = startRow; ree <= endRow; ree++) {
// if the value in column D is "Approved", move the row to target sheet
cellValue = ss.getRange("C1:E1");
if (cellValue.getValue().match(re)) {
// insert a new row at the second row of the target sheet
MoveDatatoThisSheet.insertRows(2, 1);
// move the entire source row to the second row of target sheet
var rangeToMove = ActiveSheet.getRange(/*startRow*/ getRow, /*startColumn*/ 1, /*numRows*/ 1, /*numColumns*/ ActiveSheet.getMaxColumns());
rangeToMove.moveTo(MoveDatatoThisSheet.getRange("A2"));
// add date and time of when approved to target row in column E
MoveDatatoThisSheet.getRange("E2").setValue(Date());
// delete row from source sheet
ActiveSheet.deleteRow(cellValue, 1);
}
}
}
Your loop never uses the variable ree, it only operates with cellValue = ss.getRange("C1:E1").
Another problem is that deletion shifts the rows under the deleted one, possibly causing subsequent operations to act on a wrong row. When you go through an array of rows, deleting some of them, do it bottom up, not top down.
for (var ree = endRow; ree >= startRow; ree--) {
var rangeToCheck = ss.getRange(ree, 3, 1, 3); // 3 columns starting with column 3, so C-E range
if (rangeToCheck.getValues()[0].join().match(re)) { // joining values before checking the expression
MoveDatatoThisSheet.insertRows(2,1);
var rangeToMove = ActiveSheet.getRange(/*startRow*/ getRow, /*startColumn*/ 1, /*numRows*/ 1, /*numColumns*/ ActiveSheet.getMaxColumns());
rangeToMove.moveTo(MoveDatatoThisSheet.getRange("A2"));
// add date and time of when approved to target row in column E
MoveDatatoThisSheet.getRange("E2").setValue(Date());
// delete row from source sheet
ActiveSheet.deleteRow(ree);
}
}
If the goal is to check only column D (say), the code simplifies slightly
var rangeToCheck = ss.getRange(ree, 4); // column D in row ree
if (rangeToCheck.getValue().match(re)) { // joining values before checking the expression
Performance
As Google recommends, one should avoid multiple calls to getValues / setValues and such, instead grabbing all necessary data at once, processing it, and making batch changes at once. E.g., instead of placing it a row in another sheet, add it to an array; when the loop ends, place the entire array in that sheet.
I have used the filter function =FILTER('check-in'!A8:G,'check-in'!C8:C=C4) to filter stuff from my 'check-in' sheet in my 'check-out' sheet. I have also made my first column of 'check-out' in a way to copy the row to a sheet named 'database' once the first column of rows contain "y" (means yes). It works, but when the first row is selected (which includes the filter function), it also copies the formula, and the database sheet will not store more data after that. Any advice would be appreciated.
function onEdit(event) {
assumes source data in sheet named Needed
target sheet of move to named Acquired
test column with yes/no is col 4 or D
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "check-out" && r.getColumn() == 1 && r.getValue() == "y") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Database");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
You may copy only values:
copyTo(destination, options)
Copies the data from a range of cells to another range of cells. By
default both the values and formatting are copied, but this can be
overridden using advanced arguments.
// The code below will copy only the values of the first 5 columns over
// to the 6th column.
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange("A:E").copyTo(sheet.getRange("F1"), {contentsOnly:true});
}
in your case:
s.getRange(row, 1, 1, numColumns).copyTo(target, {contentsOnly:true});
I am making a lending library for books with one sheet to show what is currently borrowed (on sheet Borrowed). Every other sheet is someone's name (called Name in my example), showing what they own that can be borrowed. I want to copy the row to the Borrowed sheet when "Borrowed" is in column C, and when it is changed back to "Returned" from either Borrowed or Name, remove it from the Borrowed sheet. So they need to be linked somehow. I had tried using query= before but couldn't edit the status of the book on Borrowed, it would just break the row.
This code is working to get the row copied over to Borrowed, but I'm not sure how to accomplish the returned part.
function onEdit(event) {
// source data in sheet named Name
// target sheet named Borrowed
// test column with yes/no is col 3 or C
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Name" && r.getColumn() == 3 && r.getValue() == "Borrowed") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Borrowed");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1,1,numColumns);
s.getRange(row, 1, 1, numColumns).copyTo(target);
}
}
Here is a hybrid approach, which uses spreadsheet functions in one direction (from Master sheet to Borrowed), and a script to move things in the opposite direction.
The Borrowed sheet contains the formula
=iferror(filter({row(Master!A:C), Master!A:C}, Master!C:C = "Borrowed"), "No books are borrowed at present")
This displays the records of borrowed books (assumed to be in columns A:C), preceded by the row number of each book in the master sheet. The row number helps in linking the records between sheets. (As a side effect, the data in Borrowed sheet moves to the right by one column).
If book status is changed to Returned from Master sheet, it goes away from Borrowed automatically. The tricky part is dealing with the edits to Borrowed sheet. This is what this script is for.
function onEdit(e) {
var ss = e.source;
var sheet = e.range.getSheet();
var row = e.range.getRow();
var col = e.range.getColumn();
var entry = (typeof e.value == 'object' ? '' : e.value.toLowerCase());
if (sheet.getName() == 'Borrowed' && col == 4 && entry == 'returned') {
e.range.clear();
SpreadsheetApp.flush();
var originalRow = sheet.getRange(row, 1).getValue();
ss.getSheetByName('Master').getRange(originalRow, 3).setValue('Returned');
}
}
The script checks that the user indeed put "Returned" (case insensitive) in column 4 (D) of sheet Borrowed. If so, it notes the row number and clears the edited cell. This restores the functionality of filter function, returning the sheet to its previous state. The script then reads the original row number from column A of Borrowed, and edits the appropriate cell of Master sheet. As a result of this edit, the Borrowed sheet no longer has the row with the returned book.
Yes, this is a somewhat roundabout way to do things... but it works.