0

I am using a modified version of this code. Where the goal is to copy/move a row to another sheet based on a dropdown value. I addition when the dropdown value is changed in sheet 2, after the row has been moved the row should be copied back to sheet 1.

  1. I do have some working code, but it breaks the Don't repeat yourself principle, because the code is repeating it self multiple times. That's why I tried to create a custom function moveWhenDone(); where only the targetSheet variable is unique and is passed as a argument.

For some reason, this code does not work when put in the function and I don't understand why?

  1. Another issue I am facing is regarding the sortSheets(); function, both sheet 1 and sheet 2 have a filter on range A:J sorted by column 1. After the row is copied I need the sheets to re-sort to reflect the changes. For some reason this ONLY works on sheet 1, after I edit a cell in the sheet 1. For sheet 2, no sorting, even after a cell edit.

How can both the sheets be re-sorted after the row is copied?

UPDATE Link to test sheet

function onEdit(event) {
  // assumes source data in sheet 1 named ASSIGMNMENTS
  // target sheet 2 of move to named DONE
  // getColumn with check-boxes is currently set to colu 7
  var act = SpreadsheetApp.getActiveSpreadsheet();
  var src = event.source.getActiveSheet();
  var r = event.source.getActiveRange();


  if(src.getName() == "ASSIGMNMENTS" && r.getColumn() == 7 && r.getValue() == "Done") {


    // Working but breaks the "Don't repeat yourself" principle
    /*var row = r.getRow();
    var numColumns = src.getLastColumn();
    var targetSheet = act.getSheetByName("DONE");
    var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    src.getRange(row, 1, 1, numColumns).copyTo(target);  
    src.deleteRow(row);*/

    var targetSheet = act.getSheetByName("DONE");
    moveWhenDone(targetSheet);


  } else if(src.getName() == "DONE" && r.getColumn() == 7 && r.getValue() != "Done") {

    // Working but breaks the "Don't repeat yourself" principle
    /*var row = r.getRow();
    var numColumns = src.getLastColumn();
    var targetSheet = act.getSheetByName("ASSIGMNMENTS");
    var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    src.getRange(row, 1, 1, numColumns).copyTo(target);  
    src.deleteRow(row);*/


    var targetSheet = act.getSheetByName("ASSIGMNMENTS");
    moveWhenDone(targetSheet);

  } 

  sortSheets();
}


// Only work on ASSIGMNMENTS (sheet 1)
function sortSheets() {
  SpreadsheetApp.flush();
  var acticeSheet = SpreadsheetApp.getActiveSpreadsheet();
  acticeSheet.getRange("A2:Z").sort([{column: 1, ascending: true}]);
}


// Do not work when called from onEdit
function moveWhenDone(targetSheet) {
    var source = event.source.getActiveSheet();
    var row = r.getRow();
    var numColumns = source.getLastColumn();
    var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);

    source.getRange(row, 1, 1, numColumns).copyTo(target);  
    source.deleteRow(row);
}
1
  • 1
    Can you please provide a sample sheet. Share a test sheet Commented Sep 21, 2021 at 15:54

1 Answer 1

1

Here are the issues why your code is not working:

  1. You are using event and r variables in your moveWhenDone() function which is not defined. event and r variables are only accessible in onEdit() unless you pass it as an argument to your moveWhenDone()
  2. The reason why your sort function only works on the active sheet is because you used SpreadsheetApp.getActiveSpreadsheet(); which returns a Spreadsheet object. When getRange() is used, it will get the range on the active sheet in your spreadsheet unless you provide the sheet name as part of your A1 Notation (example, "Done!A2:Z")

By the way, I didn't get your point when you mentioned "Don't repeat yourself principle". It somehow contradicts in your statement where "when the dropdown value is changed in sheet 2, after the row has been moved the row should be copied back to sheet 1."

Here is a sample code to move row data from sheet1 to sheet2 and vise-versa including the sorting:

function onEdit(event) {
  // assumes source data in sheet 1 named ASSIGMNMENTS
  // target sheet 2 of move to named DONE
  // getColumn with check-boxes is currently set to colu 7
  var act = SpreadsheetApp.getActiveSpreadsheet();
  var src = event.source.getActiveSheet();
  var r = event.source.getActiveRange();
  if(src.getName() == "ASSIGMNMENTS" && r.getColumn() == 7 && r.getValue() == "Done") {

    // Working but breaks the "Don't repeat yourself" principle
    var row = r.getRow();
    var numColumns = src.getLastColumn();
    var targetSheet = act.getSheetByName("DONE");
    var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    src.getRange(row, 1, 1, numColumns).copyTo(target);  
    src.deleteRow(row);
    sortSheets()
  } else if(src.getName() == "DONE" && r.getColumn() == 7 && r.getValue() != "Done") {

    // Working but breaks the "Don't repeat yourself" principle
    var row = r.getRow();
    var numColumns = src.getLastColumn();
    var targetSheet = act.getSheetByName("ASSIGMNMENTS");
    var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
    src.getRange(row, 1, 1, numColumns).copyTo(target);  
    src.deleteRow(row);
    sortSheets()
  } 
}

function sortSheets() {
  SpreadsheetApp.flush();
  var sheetNames = ["ASSIGMNMENTS", "DONE"];
  sheetNames.forEach(sheet => {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheet);
    sheet.getRange("A2:H").sort([{column: 1, ascending: true}]);
  });
}

Modifications done:

  • I removed moveWhenDone() since I didn't fully understood its purpose to prevent "Don't repeat yourself principle"
  • Instead of sorting the sheets every time the onEdit() is triggered, I put the sort function when a row was moved to a different sheet.
  • I modified the sortSheets() to loop specific sheets listed in sheetNames variable. I changed the range to "A2:H" because the sample sheet provided has mismatch in number of columns. (ASSIGNMENTS sheet has columns A-Y, while DONE sheet has columns A-M, Hence range "A2:Z" cannot be used)

Sample Output:

enter image description here


If you really want to make moveWhenDone() work, you can pass the event and r variables in onEdit(). Sample moveWhenDone(targetSheet, event, r).

But keep in mind that if you do that, what will happen is that you will basically move the current row twice to your destination sheet.

Example:

enter image description here

  • If you changed Assignment 2 to "Done", its succeeding row will also be moved to another sheet. Hence both Assignment 2 and 5 will be moved even if Assignment 5 is not yet "Done"
Sign up to request clarification or add additional context in comments.

2 Comments

Please let me know if you have some issues with the solution provided so i could update accordingly. Please do clarify your goal when you mentioned "Don't repeat yourself principle" if the current solution is not the one you are expecting.
Thanks for solving this issue, and for clearing up my confusion regarding the workings of the moveWhenDone() function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.