【问题标题】:Google Apps Script is creating calendar entry twiceGoogle Apps 脚本两次创建日历条目
【发布时间】:2020-10-20 22:36:05
【问题描述】:

我已经将一个 Google Apps 脚本混合在一起,以便根据我的 Google 工作表中的值在日历中创建一个事件。该脚本应在以下条件下工作:

  1. 每当添加新行时(由触发器实现 - 第一个函数)
  2. 仅适用于电子表格的最后一行
  3. 仅当“id”单元格 (28) 为空时才创建事件

然后它应该创建日历事件并使用事件 ID 填充单元格 28。

当客户在我的网站上填写表格时会创建新行。我在具有 Google Sheets 插件的 WordPress 中使用 Ninja Forms。所以填写好的表格会自动添加到工作表中,然后这个函数就会触发。

一切都几乎正常工作。当我手动测试时(例如,我删除最后一行中的 id 单元格,或者我创建一个新行或复制现有行)它工作得很好。 在单元格 28 中没有事件 ID 的情况下创建事件,并且它成功地使用 ID 填充单元格 28。太好了!

但是,当使用 WordPress 表单创建行时,我得到 两个 日历事件。 IE - 就像函数运行两次一样。每个事件都是相同的,并且都是同时创建的。

我猜这与表单与工作表的集成方式有关。它以某种方式触发了我的功能两次。我尝试在函数中的不同点使用 Utilities.sleep 并使用不同的值来查看 strps 之间的等待是否有帮助,但无济于事。

谁能想到我可以阻止这种情况发生的方法?是否有某种检查可以内置到我的功能中?还是我错过了一些明显的东西?我真的很感激任何建议。 这是我的代码:

function initializeTrigger(){ // run once only to create the trigger
  var sheet = SpreadsheetApp.getActive();
 ScriptApp.newTrigger("NewCalEvent")
   .forSpreadsheet(sheet)
   .onChange()
   .create();
}

function NewCalEvent() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('Bookings2');
  var row = sheet.getLastRow();
  var calId = "xxxyyy@group.calendar.google.com";
  var cal = CalendarApp.getCalendarById(calId);
  var date = sheet.getRange(row, 1).getValue();
  var title = sheet.getRange(row, 26).getValue();
  var tz = sheet.getRange(row, 23).getValue();
  var tstart = new Date(sheet.getRange(row, 32).getValue());
  var tstop = new Date(sheet.getRange(row, 33).getValue());
  var loc = sheet.getRange(row, 2).getValue();
  var desc = sheet.getRange(row, 27).getValue();
  var guests = sheet.getRange(row, 29).getValue();
  var id = sheet.getRange(row, 28).getValue();
if (id == ""){    
  var newEvent = cal.createEvent(title, tstart, tstop, {description:desc,location:loc,guests:guests,sendInvites:true}).getId();
  sheet.getRange(row, 28).setValue(newEvent)
  }
}

【问题讨论】:

  • 尝试使用事件对象 changeType 来指定一个唯一的更改类型,也可能你得到一个虚假的额外触发器,尝试对其进行测试。
  • trigger event object里面有一个叫changeType的参数
  • 在脚本执行页面上,您应该能够看到每个脚本执行的条目。这可以帮助您准确了解表单是否触发了您的脚本两次是否发生了其他事情。
  • 首先学习 javascript 会极大地促进学习 Google Apps 脚本。对 html 和 css 的合理了解也是非常有用的。

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


【解决方案1】:

可能的解决方案:

添加检查以查看是否已为此时间创建日历事件。

更多信息:

由于尚不清楚此触发器重复的确切来源,因此绕过创建两次的事件的一种方法是在日历中搜索指定时间范围内的事件,其中包含您要输入的描述,然后换行检查中的事件创建代码,因此它仅在事件尚不存在时运行。

代码片段:

// ...
var id = sheet.getRange(row, 28).getValue();
var events = cal.getEvents(tstart, tstop, {search: desc})
      .map(function(e) {
        try {
          return e.getDescription();
        }
        catch {
          return "";
        }
      });

if (!events.includes(desc)) {
  if (id == ""){
    var newEvent = cal.createEvent(title, tstart, tstop,
      {description:desc,location:loc,guests:guests,sendInvites:true}).getId();
    sheet.getRange(row, 28).setValue(newEvent)
  }
}

这样,如果脚本运行两次,那么由于第二次事件已经存在,就不会再次创建。

注意:这会检查所有日历事件是否存在于tstarttstop 的时间范围内,并且描述为desc。如果您碰巧在此时间范围内有其他具有相同描述的事件,则此脚本可能不会按预期运行。

参考资料:

【讨论】:

  • 是的!你传奇。效果很好!非常感谢!我打算放弃并将触发器更改为基于时间(每分钟),因为这似乎可以解决问题,但如果超过一个人在一分钟内填写表格,我可能会陷入困境。这是一个更清晰和更好的解决方案。非常感谢您花时间写出来并帮助我。
  • 只是为了我自己的教育,我稍微更改了您的代码以使用标题 - getName() - 它似乎仍然有效。有什么理由我会改用描述吗?
  • @Luke 没有理由,我只是选择了描述,因为它更有可能是独一无二的(我不知道你的数据集,所以可能是像“每周团队会议”这样的通用标题或类似的东西到这个)
  • 啊,这很有意义。在我的具体情况下,标题包括客户的姓名和具体时间,所以我认为我可以继续使用它。但你的答案绝对是最适合一般用途的。再次感谢您提供简洁、清晰和有用的答案。你救了我很多挫折。
  • 嗨@rafa-guillermo 很抱歉再次提出这个问题。我刚刚注意到——即使脚本完美地完成了这项工作——我也会在事件被抑制时记录错误。有没有办法抑制这些错误?请参阅此处的示例:imgur.com/2CNhAHa
猜你喜欢
  • 2014-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多