Javascript 谷歌应用程序脚本创建日历条目两次

Javascript 谷歌应用程序脚本创建日历条目两次,javascript,google-apps-script,google-sheets,google-calendar-api,Javascript,Google Apps Script,Google Sheets,Google Calendar Api,我将一个谷歌应用程序脚本混合在一起,根据我的谷歌工作表中的值在日历中创建一个事件。脚本应在以下条件下工作: 每当添加新行时(通过触发器实现-第一个函数) 仅适用于电子表格上的最后一行 仅当“id”单元格(28)为空时创建事件 然后,它应该创建日历事件并用事件ID填充单元格28 新行是在客户在我的网站上填写表单时创建的。我在WordPress中使用忍者表单,它有一个谷歌表单插件。因此,填写的表单将自动添加到工作表中,然后此函数将启动 一切都很顺利。当我手动测试时(例如,我删除最后一行中的id单元格

我将一个谷歌应用程序脚本混合在一起,根据我的谷歌工作表中的值在日历中创建一个事件。脚本应在以下条件下工作:

  • 每当添加新行时(通过触发器实现-第一个函数)
  • 仅适用于电子表格上的最后一行
  • 仅当“id”单元格(28)为空时创建事件
  • 然后,它应该创建日历事件并用事件ID填充单元格28

    新行是在客户在我的网站上填写表单时创建的。我在WordPress中使用忍者表单,它有一个谷歌表单插件。因此,填写的表单将自动添加到工作表中,然后此函数将启动

    一切都很顺利。当我手动测试时(例如,我删除最后一行中的id单元格,或者创建新行,或者复制现有行),它可以完美地工作。只有在第28单元中没有事件ID时才会创建该事件,并且它成功地用ID填充了第28单元。太好了

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

    我猜这与表单如何与表单集成有关。不知怎的,它两次触发了我的功能。我试过在函数中的不同点使用Utilities.sleep,使用不同的值来查看strp之间的等待是否有帮助,但没有效果

    有人能想出一个办法阻止这种事情发生吗?我是否可以在我的函数中建立某种检查?还是我错过了一些明显的东西?如果有任何建议,我将不胜感激。 这是我的密码:

    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)
      }
    }
    
    可能的解决办法: 添加一项检查,查看是否已为此时间创建日历事件

    更多信息: 由于不清楚此触发器复制的确切来源,避免创建两次事件的一种方法是,在日历中搜索指定时间范围内具有您要输入的描述的事件,然后将事件创建代码包装在检查中,以便仅在事件尚不存在时运行

    代码段:
    /。。。
    var id=sheet.getRange(第28行).getValue();
    var events=cal.getEvents(tstart,tstop,{search:desc})
    .map(功能(e){
    试一试{
    返回e.getDescription();
    }
    抓住{
    返回“”;
    }
    });
    如果(!事件包括(描述)){
    如果(id==“”){
    var newEvent=cal.createEvent(标题、tstart、tstop、,
    {description:desc,loc,guests:guests,sendinvests:true});
    sheet.getRange(第28行).setValue(newEvent)
    }
    }
    
    这样,如果脚本运行两次,那么由于第二次事件已经存在,将不会再次创建它

    NB:此项检查在
    tstart
    tstop
    的时间范围内是否存在描述为
    desc
    的所有日历事件。如果在此时间范围内碰巧有其他具有相同描述的事件,则此脚本的行为可能不符合预期

    我希望这对你有帮助

    参考资料:

    尝试使用事件对象changeType指定唯一的更改类型。如果您获得了一个虚假的额外触发器,请尝试对其进行测试。查看脚本执行页面上包含名为changeType的参数,您应该能够看到每个脚本执行的条目。这可以帮助你准确地知道表单是否会触发两次你的脚本,如果其他事情正在发生。同时,对html和css有一定的了解也是非常有用的!你是个传奇人物。那很有效!非常感谢!我打算放弃,将触发器改为基于时间的(每分钟),因为这似乎解决了问题,但如果一分钟内有多人填写表单,我可能会陷入困境。这是一个更清晰、更好的解决方案。非常感谢您花时间编写并帮助我。只是为了我自己的教育,我对您的代码做了一些修改,使用了title-getName(),而且似乎仍然有效。有什么理由我会用描述来代替吗?@Luke没有理由,我只是选择了描述,因为它更可能是唯一的(我不知道你的数据集,所以可能是像“每周团队会议”这样的通用标题或类似的东西)啊,这很有意义。在我的例子中,标题包括客户的名字和具体时间,所以我认为我可以继续使用它。但你的答案绝对是最适合一般使用的。再次感谢您提供的周到、清晰和有用的答案。你帮我省去了很多挫折。嗨@rafa guillermo很抱歉再次提起这件事。我只是注意到,即使脚本做得很好,我也会在事件被抑制时记录错误。有没有办法消除这些错误?有关示例,请参见此处: