简体   繁体   中英

Google Apps Script double deleting rows in spreadsheet

function onEdit() {
var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
var lastRowOpen = openRequests.getLastRow();

var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
var lastRowClose = closedRequests.getLastRow();

var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();

for (var i = 0; i < lastRowOpen; i++)
{
    if (closed[i][0].toString() == 'Yes')
    {
        var line = i+2;
        if (closedRequests.getLastRow() == 1)
        {
            openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
            closedRequests.getRange(2,9,1,1).setValue(new Date());
            openRequests.deleteRow(line);
        }
        else
        {
            openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
            closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
            openRequests.deleteRow(line);
        }
    }
}

}

I have set up a trigger to run onEdit. What it does is check a column called Closed to see if it says Yes . The Closed column has a data validation drop down menu with the value Yes in it.

So when I click on the drop down menu and select Yes , it should copy the whole row to another sheet called Closed Requests then delete that row from the spreadsheet called Open Requests .

The issue I am having is that about 50% of the time, it deletes the row I select Yes to but it ALSO deletes the row below it (and about 50% of the time when this happens, only some times does the second deleted row show up in Closed Requests , the other times the whole row just disappears forever unless I undo).

From what I can tell, the deleteRow() function deletes the whole row and shifts all rows below it up a row to fill in the blank. So the row below the one meant to be deleted gets shifted up to the same row and also gets deleted. I don't know why the function is getting called twice though.

I tried adding some delays but it does not seem to be working.

function onEdit(e) {
  var eRange = e.source.getActiveRange();
  var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
  var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
  var nextRowClose = (closedRequests.getLastRow()?closedRequests.getLastRow()+1:2);

  if(eRange.getSheet().getName()=="Open Requests" && eRange.getColumn()==8 && eRange.getValue()=="Yes") {
    openRequests.getRange(eRange.getRow(), 1, 1, 9)
      .copyTo(closedRequests.getRange(nextRowClose, 1));
    closedRequests.getRange(nextRowClose, 9).setValue(new Date());
    openRequests.deleteRow(eRange.getRow());
  }
}

Could try iterating backwards as it was mentioned to me . Throwing in a SpreadsheetApp.flush() after the delete may help too.

@Jack, I have a similar use case to you. My code is the backwards one that BryanP discusses. My code is more or less here: "Batch removal of task items where status = 'Done'" . It is because I remove them in a batch that I use the backwards method whereby the removal of a row with a higher row number will not disturb the row number of any rows with a lower row number.

But you are not removing rows in batch mode, so maybe backwards shouldn't make a difference (perhaps unless two users use the sheet and delete at the same time?)

So thought I'd try your code. I shoe horned your code into the onedit() function that is already present on my spreadsheet (which is used to colour rows red after a period of inactivity, and to put in a timestamp once the task is actually attended).

Then to test I used a copy of one of our spreadsheet which had already 50 rows/tasks in it. I manually filled in the required cells in a row and selected Done from the cell with the dropdown (I changed your code to expect "Done" rather than "Yes"). I repeated this for 20 rows.

The Result: Your code succeeded as you had expected it to every one of the 20 times ... no double deletes, always copying data across. It worked for me without introducing delays nor SpreadsheetApp.flush().

I don't have a solid suggestion I am afraid. In passing I mention the known fault where the spreadsheet has not properly refreshed itself, so does not show the deleted rows; this can be checked for by manually refreshing the spreadsheet when this fault appears. (However, the indications of this fault does not seem to logically fit with your report about the double copying over of two sequential rows.)

Thread lock? Sounds like a thread lock problem. Try:

function onEdit() {

 // ****** add lock code
 var lock = LockService.getPublicLock();
 var hasMutex = lock.tryLock(100);
 if(hasMutex==false) {
   return;
 }
 // *** end

 var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
 var lastRowOpen = openRequests.getLastRow();

 var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
 var lastRowClose = closedRequests.getLastRow();

 var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();

 for (var i = 0; i < lastRowOpen; i++)
 {
    if (closed[i][0].toString() == 'Yes')
    {
       var line = i+2;
       if (closedRequests.getLastRow() == 1)
       {
          openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
          closedRequests.getRange(2,9,1,1).setValue(new Date());
          openRequests.deleteRow(line);
       }
        else
       {

   openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
        closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
        openRequests.deleteRow(line);
        }
      }
  }


 // ****** add lock code
  lock.releaseLock();    

 // *** end

} 

Questions:

1) how many people were using the spreadsheet at the time.

2) how often does it happen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM