Google Apps脚本会双重删除电子表格中的行

时间:2013-01-12 08:33:30

标签: javascript google-apps-script google-sheets

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);
        }
    }
}

}

我已经设置了一个触发器来运行onEdit。它的作用是检查一个名为Closed的列,看它是否显示YesClosed列有一个数据验证下拉菜单,其中包含值Yes

因此,当我点击下拉菜单并选择Yes时,它应将整行复制到另一张名为Closed Requests的工作表,然后从名为Open Requests的电子表格中删除该行。< / p>

我遇到的问题是大约50%的时间,它会删除我选择Yes的行,但它也会删除它下面的行(大约50%的时间发生这种情况,只有有时候第二个删除的行会显示在Closed Requests中,有时候整行会永远消失,除非我撤消。)

据我所知,deleteRow()函数删除整行并将其下方的所有行向上移动以填充空白。因此,要删除的行下方的行会向上移动到同一行并被删除。我不知道为什么函数被调用了两次。

我尝试添加一些延迟,但似乎没有效果。

4 个答案:

答案 0 :(得分:5)

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());
  }
}

答案 1 :(得分:1)

可以尝试向后迭代,因为它是mentioned to me。删除后投入SpreadsheetApp.flush()也可能有所帮助。

答案 2 :(得分:1)

@Jack,我有一个类似的用例。我的代码是BryanP讨论的向后代码。我的代码或多或少在这里:"Batch removal of task items where status = 'Done'"。这是因为我使用向后方法批量删除它们,因此删除具有较高行号的行不会干扰具有较低行号的任何行的行号。

但是你不是在批处理模式中删除行,所以也许倒退不应该有所作为(可能除非两个用户同时使用工作表并删除?)

以为我会尝试你的代码。我将你的代码添加到我的电子表格中已经存在的onedit()函数中(该函数用于在一段时间不活动后将行变为红色,并在实际参与任务后放入时间戳)。

然后测试我使用了一个已经有50行/任务的电子表格的副本。我手动填写连续所需的单元格,并使用下拉列表从单元格中选择完成(我将代码更改为期望“完成”而不是“是”)。我重复了20行。

结果:您的代码成功了,因为您对20次中的每一次都有预期...没有双重删除,总是复制数据。它对我有用而没有引入延迟,也没有引入SpreadsheetApp.flush()。

我恐怕没有可靠的建议。顺便提一下,我提到了电子表格没有正确刷新的已知错误,因此没有显示已删除的行;当出现此故障时,可以通过手动刷新电子表格来检查此问题。 (但是,这个错误的迹象似乎在逻辑上不符合您关于两个连续行的双重复制的报告。)

答案 3 :(得分:0)

线程锁定?听起来像是线程锁定问题。尝试:

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

} 

问题:

1)当时有多少人在使用电子表格。

2)多久发生一次。