我有一个带有一些功能的电子表格。其中之一是 onEdit(event) 函数,它根据条件将一些值复制到其他工作表。这是代码(经过简化,但重要部分完好无损):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() === "Lista" && r.getColumn() === 9 && r.getValue() === "Posicionada") {
var sheetname = s.getRange(r.getRow(),3).getValue();
var columnRef = s.getRange(r.getRow(),4).getValue();
var row = s.getRange(r.getRow(),5).getValue();
var targetSheet = ss.getSheetByName("Mapa " + sheetname);
var headers = targetSheet.getRange(1, 1, 1, targetSheet.getLastColumn());
for (var i = 0; i < headers; i++) {
if (headers[i] === columnRef) {
break;
}
}
var column;
if (columnRef === "A1") {
column = 2;
}
else if (columnRef === "A2") {
column = 3;
}
else if (columnRef === "B1") {
column = 4;
}
else if (columnRef === "B2") {
column = 5;
}
if (sheetname === "N2") {
row = row - 30;
}
if (sheetname === "N3") {
column = column - 10;
row = row - 42;
}
targetSheet.getRange(row,column).setValue(s.getRange(r.getRow(), 1, 1, 1).getValue());
}
}
当我手动编辑单元格时,代码可以正常工作。但是,我有一个代码,当用户按下侧边栏中的按钮时编辑单元格,这是代码:
function positionMU(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().activate();
var cellLevel = cell.offset(0,2);
var cellLetter = cell.offset(0,3);
var cellNumber = cell.offset(0,4);
var cellStatus = cell.offset(0,8);
var dbq = "Posicionada";
var fora = "Pendente de recebimento";
if (cellStatus.getValue() == "Aguardando posicionamento"){
cellStatus.setValue(dbq); //attention in this line
}
else if (cellStatus.getValue() == "Aguardando saída"){
cellStatus.setValue(fora);
var cellExitDate = cell.offset(0,6);
cellExitDate.setValue(getDate());
}
}
如您所见,该函数使用 setValue() 更改单元格内容,但是,当我使用此函数时,单元格的值发生更改,但 onEdit() 触发器不起作用。
如何使 onEdit() 触发器识别使用 setValue() 所做的更改?
你是对的。 onEdit() 仅在手动编辑范围时触发。从这里可以看出,当用户更改某个值时,onEdit() 就会触发。
我通过使函数将值插入到我的 onEdit 响应的列中来测试该函数,但没有任何反应。包括我能想到的各种其他技术。在这里最好的做法是建议将此作为 App Script 的问题跟踪器的增强功能。
但是,我通过编写另一个函数来使其工作,当脚本中的另一个函数对工作表进行更改时要调用该函数。这些是我写的测试函数:
function addValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var book = "Book";
var cancel = "Cancel";
var maxRow = range.getLastRow()+1;
for(var i=0; i<4; i++)
{
if (i%2 == 0)
{
sheet.getRange(maxRow, 1).setValue(book);
autoChanges(maxRow);
}else{
sheet.getRange(maxRow, 1).setValue(cancel);
autoChanges(maxRow);
}
maxRow++;
}
}
自动更改功能:
function autoChanges(row)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var data = range.getValues();
var response = "";
sheet.getRange(row, 2).protect();
response = data[row-1][0];
if (response == "Book")
{
sheet.getRange(row, 2).canEdit();
}else{
sheet.getRange(row, 2).setValue("--NA--");
}
}
不是最优雅的解决方案,但这似乎是您想要做的事情的唯一解决方法。
调用 range.setValue() 不会触发 onEdit 事件有一些很好的理由,其中大多数都与无限递归有关。事实上,您可以在 onEdit() 中自己调用 setValue()。这将触发递归调用,从我看来,您没有处理基本情况的规定,因此如果 setValue() 执行您想要的操作,您的代码将会爆炸。
为什么不简单地将所有代码从事件处理程序中取出,并将其放入另一个函数中:
function onEdit (e) {
return handleEdits(e.range);
}
function handleEdits(r) {
s = r.getSheet();
ss = s.getParent();
//the rest of your code should drop right in.
}
然后,在 autoChanges 函数中,在调用 setValue() 后,继续调用 handleEdits,将其传递给适当的范围。
如果你喜欢玩火,我个人也喜欢,你可以在进行更改后调用 onEdit(e) 函数。 只需发送一个对象,无论 e 对象调用和使用什么。
对我来说,我只需要添加:
var e={};
e.range=the range you are making a change to in the script;
e.source = SpreadsheetApp.getActiveSpreadsheet();//or make sure you have the sheet for wherever you are setting the value
e.value=whatever value you are setting
e.oldValue=if you onEdit needs this, set it here
//if you are using any of the other standard or special properties called by your onEdit...just add them before calling the function.
onEdit(e);//call the function and give it what it needs.