GoogleScript: How to CopyRow before Delete the same - google-apps-script

Situation:
I find this script, that delete the rows when the text in the column B change to "Closed". I want to copy the row before to delete into other sheet called historic.
Action:
The script should be copy the row when the the status is "Closed" in other sheet called "Historic" in the same spreadsheeet.
Then when the first point is completed should be delete the rows in the activesheet.
SCRIPT DELETE ROWS:
function DeleteRow(e) {
try {
var ss = e.source; // Just pull the spreadsheet object from the one already being passed to onEdit
var s = ss.getActiveSheet();
// Conditions are by sheet and a single cell in a certain column
if (s.getName() == 'ISP1' && // change to your own
e.range.columnStart == 2 && e.range.columnEnd == 2 && // only look at edits happening in col 2 which is 2
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if ( e.value == 'Closed') { // Delete if value is zero or empty
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}
SCRIPT HISTORIC:
This script when somone update the column 5 will copy the row to other sheet called "historic".
When somone change the column 9 and select the status "Closed" the script copy the row to the historic and insert the closed date.
Now, does exist any why to do the same and improve the perfomance? I think this script is very complex and use many line.. I don't know if possible do the same better.
function Historic(e) { //CopyRows
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var r = SpreadsheetApp.getActiveRange();
var date = Utilities.formatDate(new Date(), "GMT-3", "dd/MM/yyyy HH:mm"); // Function Date + Format
// 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.
var colNumber = s.getLastColumn();
// Move row based on criteria in column 5, and if row is not the header.
if (colIndex == 5 && rowIndex != 1) {
// Get value from column 5, in the active row.
var status = s.getRange(rowIndex, colIndex).getValue();
// Do nothing if criteria value is not actually changed to something else.
if (s.getName() != 'Historic') {
// The target sheet is the one with the same name as the criteria value.
var targetSheet = ss.getSheetByName('Historic');
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(rowIndex, 1, 1, colNumber).copyTo(target);
//s.deleteRow(rowIndex); // This line delete the source row
targetSheet.getRange(targetSheet.getLastRow(), 11).setValue(s.getSheetName()); //Insert in the Column 11 the SheetName where was modify that line
}
}
else if (colIndex == 9 && rowIndex != 1 && e.value == 'Closed' ) {
// Get value from column 5, in the active row.
var status = s.getRange(rowIndex, colIndex).getValue();
// Do nothing if criteria value is not actually changed to something else.
if (s.getName() != 'Historic') {
// The target sheet is the one with the same name as the criteria value.
var targetSheet = ss.getSheetByName('Historic');
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(rowIndex, 1, 1, colNumber).copyTo(target);
targetSheet.getRange(targetSheet.getLastRow(),10).setValue(date); //This Line Insert Close Date when the user select option Close
targetSheet.getRange(targetSheet.getLastRow(),11).setValue(s.getSheetName()); //Insert in the Column 11 the SheetName where was modify that line
e.source.getActiveSheet().deleteRow(e.range.rowStart); // This line delete the source row
}
}
}

I see somone vote this question -1. I'm using the Historic the second part, this part copy and then delete the row.
If anyone have a better idea, I will appreciate your help.
Thanks So much

Related

Move Rows based on matches between 3 columns

My goal is to compare the entries', from the Data tab, First Name, Last Name, and Date of Birth to the same columns on another tab named Completed and erase the matching rows from the Data tab.
Marking a checkbox on another tab New Cases should find the row on Data, Move that row to Completed, and clear the checkbox on New Cases.
https://docs.google.com/spreadsheets/d/1sVVzW4Ga6XzYrGS-7AqwdMCqeL1-IxzRVSHG2FxMCog/edit?usp=sharing
I found a couple scripts that approached what I wanted, and I copied them into the sheet, but I don't have the expertise to get either (Move row based on cell selection) or (https://support.google.com/docs/thread/39992635?msgid=40432488) to accomplish the solution.
I was able to get something like this to work, but it only worked once, and I was only able to get it to move a row from (New Cases) to (Completed).
function onEdit(event) {
// assumes source data in sheet named New Cases
// target sheet of move to named Completed
// getColumn with check-boxes is currently set to colu 21 or V
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "New Cases" && r.getColumn() == 21 && r.getValue() == true) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Completed");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
Edit: I'm trying to get any row from "Data" where Columns C, D, AND E match any row on "Completed" to automatically delete off of the "Data" sheet.
Then, when the checkbox on "New Cases" is checked in column V, it moves the matching row from "Data" to "Completed" and unchecks the box on "New Cases" so it's ready for the next entry.
Select checkbox on New Cases Find row on Data move Data row to Completed
Delete row on Data and reset checkbox on new cases.
function onEdit(e) {
const nsh = e.range.getSheet();
if (nsh.getName() == "New Cases" && e.range.columnStart == 22 && e.range.rowStart > 1 && e.value() == "TRUE") {
const nrg = nsh.getRange(e.range.rowStart, 1, 1, nsh.getLastColumn());
const nvs = nrg.getValues().flat();//row
const dsh = e.source.getSheetByName("Data");
const dvs = dsh.getRange(2, 1, dsh.getLastRow() - 1, dsh.getLastColumn()).getValues();
const csh = e.source.getSheetByName("Completed");
const tgt = csh.getRange(csh.getLastRow() + 1, 1);
for (let i = 0; i < dvs.length; i++) {
if (dvs[i][2] == nvs[2] && dvs[i][3] == nvs[3] && dvs[i][4] == nvs[4]) {
let drg = dsh.getRange(i + 1, 1, 1, dsh.getLastColumn());
drg.copyTo(tgt);
dsh.deleteRow(i + 1);
break;
}
}
e.range.setValue("FALSE");//reset the checkbox
//e.range.offset(0,1).setValue(new Date());//you should consider doing this so that you know that it has been moved. The way it setup now it would put the timestamp in column W
}
}

How can I move a column to a new sheet once row 1 has a certain value?

I am using the code posted here that moves a row based on the value of a column, but I want to edit it so that it does the opposite: moves a column to a new sheet based on the value of a row.
This is what I have so far:
function onEdit(event) {
// source data in sheet named Blocks
// sheet column is moved to named Ordered
// test row with word "Done" is row 1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Blocks" && r.getRow() == 1 && r.getValue() == "Done") {
var column = r.getColumn();
var numRows = s.getLastRow();
var targetSheet = ss.getSheetByName("Ordered");
var target = targetSheet.getRange(targetSheet.getLastColumn() + 1, 1);
s.getRange(column, 1, 1, numRows).copyTo(target);
s.deleteColumn(column);
}
}
The problem is, when I tested it, it only moved the first row of that column. I want it to move the entire column and then delete it from the original sheet.
Can anyone tell me where I went wrong?
Moving Selected Columns
function onEdit(e) {
//e.source.toast('Entry');
var sh = e.range.getSheet();
if(sh.getName() == "Blocks" && e.range.rowStart == 1 && e.value == "Done") {
//e.source.toast('Ordered1')
var tsh = e.source.getSheetByName("Ordered");
var target = tsh.getRange(1,tsh.getLastColumn() + 1);
sh.getRange(2, e.range.columnStart, sh.getLastRow() -1).copyTo(target);
sh.deleteColumn(e.range.columnStart);
}
}
I used Active/Done datavalidation on row one and I only moved from row two to last row and then deleted the entire column including the validated cell.

is there a Google Apps Script function that tells a script to run once a specific column is populated?

I'm creating a script to automatically sort rows, but I don't want the rows to move until all cells in that row have been populated
I have the following code:
SHEET_NAME = "New";
SORT_DATA_RANGE = "A2:M999";
SORT_ORDER = [
{column: 2, ascending: true}, // 3 = column number, sorting by
descending order
{column: 1, ascending: true}, // 1 = column number, sort by ascending
order
];
function onEdit(e){
multiSortColumns();
}
function multiSortColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(SHEET_NAME);
var range = sheet.getRange(SORT_DATA_RANGE);
range.sort(SORT_ORDER);
ss.toast('Sort complete.');
}
However, as soon as I populate column 2, the row sorts before I can populate columns 3-13.
I expect to have the rows sorted after all other columns have been populated.
You want to sort columns using an onEdit trigger on cell B2, but only if cells in row 2, columns 3 to 13, have already been populated.
The following answer addresses the logic required to execute the sort only if certain conditions are met. There are a couple of key elements to this:
use the Event Objects - it makes life easier.
get the data for row2, columns 3 to 13 (editedsheet.getRange(editedRow,3,1,11).getValues();) so that it can be evaluated in the loop.
IF#1: test whether the edited cell was B2 (if (editedRow == 2 && editedCol == 2){)
if yes, then loop through the value range (for (var i=0;i<rowdata[0].length;i++){)
if no, then abort.
IF#2: inside the loop: test whether every value exists (if (rowdata[0][i] > 0){)
if OK, then next item in the loop
if not OK, then abort by using return;
if you get to the end IF#1, then do the sort.
function onEdit(e) {
//so5856469701
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get edited variables
var editedCell = e.range;
var editedRow = editedCell.getRow();
var editedCol = editedCell.getColumn();
var editedsheet = ss.getSheetByName(e.source.getSheetName());
// Logger.log("DEBUG: Cell = "+editedCell.getA1Notation()+", row = "+editedRow+", column = "+editedCol)
//get the data from columns 3 to 13 for the edited row
var rowdata = editedsheet.getRange(editedRow,3,1,11).getValues();
//do stuff ONLY if the edited cell was B2
if (editedRow == 2 && editedCol == 2){
// Logger.log("DEBUG: edited cell was in the right row or column. Continue processing");
//loop through the data range
for (var i=0;i<rowdata[0].length;i++){
// Logger.log("DEBUG: value = "+rowdata[0][i]);
// assumes data is numeric, otheriwse test for .length>0
// if the value in the dat range >0, then
if (rowdata[0][i] > 0){
// Logger.log("DEBUG: greater than zero");
}else{
Logger.log("DEBUG: value in column "+(+i+1)+" is NOT greater than zero; script abort");
return;
}
}
Logger.log("got through the if; now run the sort");
// to get this far, all the cells in columns 3 to 13 have values so the sort can proceed
// insert sort code
}else{
Logger.log("DEBUG: edited cell wasnt in the right row or column");
}
}

If AND statements in google script to move data to another sheet based on change in one cell and value in another

OK, I'm fairly new at doing this. I have a google spreadsheet that I populate and then run a script to create forms are created to complete tasks. My end users mark the task as completed. I am wanting entries in the spreadsheet that change to yes AND are Validate tasks to copy to another sheet (Log). I can get the entries to copy if I just have a watcher for yes but am having problems putting the other if statement for the task in there. Here is what I have for a test...
function onChange() {
// moves a row from any sheet to an archive sheet when a magic value is entered in a column
var columnNumberToWatch = /* column D */ 4; // column A = 1, B = 2, etc.
var valueToWatch = "yes";
var sheetNameToMoveTheRowTo = "LOG";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var cell = sheet.getActiveCell();
if ( sheet.getName() != sheetNameToMoveTheRowTo && cell.getColumn() == columnNumberToWatch
&& cell.getValue().toLowerCase() == valueToWatch) {
if (cell.getColumn() == 2 && cell.getValue() == "Validate") {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(cell.getRow(), 1, 1, sheet.getLastColumn())
.copyTo(targetRange);
}
}
}
It looks like you are trying to watch two separate locations with the same cell variable. You start by initializing cell as the active cell, then check that the column is #4, then in the second if statement you use cell to getColumn 2.
Maybe create a new set of variables to use for the validation check:
var activeRow=cell.getRow();
var valCheck=sheet.getRange(activeRow, 2);
then the if statement changes to:
if (valCheck.getValue() == "Validate") {

Copy over a specific range not whole row to another google sheet based on cell value

I would like to have select cells of a row copied from "Pending" sheet to "Live" sheet based on when a specific cell is edited to say "Yes".
So far I'm able to copy the whole row over when a specific cell in a column is edited to say "Yes".
I would like the specific cells in that row to copy and move onEdit, but not the whole row. For example copy, the contents of column 2,3,5,6 but not 4,7,8 etc. of the row edited in the "Pending" sheet over to the "Live" sheet.
Also though, when copying over to the "Live" sheet having column 2 of the "Pending" sheet line up with column 2 of the "Live" Sheet etc. But for column 5 and 6, they should both move over one column since column 4 wasn't copied over. So "Pending" 5 should take the place of "Live" 4 and "Pending" 6 should take the place of "Live" 5.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Pending" && r.getColumn() == 1 && r.getValue() == "Yes") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Live");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
}
}
Try This:
function onEdit(e)
{
var ss=e.source;
var sh=ss.getActiveSheet();
var rg=sh.getActiveRange();
var row=rg.getRow();
var col=rg.getColumn();
Logger.log(col);
if(sh.getName()=="Pending" && col==1 && rg.getValue()=="Yes")
{
var row = rg.getRow();
var liveSht = ss.getSheetByName("Live");
var vA=sh.getRange(row,col,1,6).getValues();
var liveA=['',vA[0][1],vA[0][2],vA[0][4],vA[0][5]];
liveSht.appendRow(liveA);
}
}