首页 > 解决方案 > 使用 onEdit 触发器将 Google 日历事件自动刷新到 Google Sheers

问题描述

我正在尝试将 Google 日历中的时间事件抓取到 Google 电子表格中。

当在我的 Google 日历中创建新的时间事件时,该事件应自动同步到我的 Google 电子表格中。这应该由onEdit事件触发器自动完成。

目前它只能通过刷新 Google 电子表格来运行。

也许有人对我的挑战有更好的解决方案。这是我的代码:

function createSpreadsheetEditTrigger() {
  var ss = SpreadsheetApp.getActive();
  ScriptApp.newTrigger('myCalendar')
      .forSpreadsheet(ss)
      .onEdit()
      .create();
}

function myCalendar(){

  var now=new Date();

 // Startzeit
  var startpoint=new Date(now.getTime()-60*60*24*365*1000);
  // Endzeit
  var endpoint=new Date(now.getTime()+60*60*24*1000*1000);

  var events=CalendarApp.getCalendarById("your-calendar-ID").getEvents(startpoint, endpoint);

  var ss=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("TEST"); 

  ss.clear(); 

  for (var i=0;i<events.length;i++) {

         ss.getRange(i+1,1 ).setValue(events[i].getTitle());
         ss.getRange(i+1,2).setValue(events[i].getDescription());
         ss.getRange(i+1,3).setValue(events[i].getStartTime());
         ss.getRange(i+1,4).setValue(events[i].getEndTime());
   }
 }

标签: google-apps-scriptgoogle-sheetsgoogle-calendar-apitriggers

解决方案


问题

在 Google 日历中创建事件时执行更新电子表格的功能。

解决方案

使用EventUpdated每次在日历中修改事件时触发的可安装触发器(例如,创建、更新或删除 - 请参阅参考资料)。从那里,您可以采用简单的方式(使用内置CalendarApp类更新电子表格中的所有数据)或困难的方式(更新通过增量同步更改的数据 - 请参阅官方指南)。

第 0 部分 - 安装触发器

/**
 * Installs Calendar trigger;
 */
function calendarTrigger() {
  var trigger = ScriptApp.newTrigger('callback name here')
  .forUserCalendar('calendar owners email here')
  .onEventUpdated()
  .create();
}

第 1 部分 - 回调(日历 -> 电子表格)

/**
 * Updates spreadsheet;
 * @param {Object} e event object;
 */
function updateSpreadsheet(e) {  
  //access spreadsheet;
  var ss = SpreadsheetApp.openById('target spreadsheet id');
  var sh = ss.getSheetByName('target sheet name');
  var datarng = sh.getDataRange(); //assumed that data is only calendar data;

  //access calendar;
  var calendar = CalendarApp.getCalendarById(e.calendarId);

  //set timeframes;
  var start = new Date();
  var end =new Date();

  //get year before and three after;
  start.setFullYear(start.getFullYear()-1);
  end.setFullYear(end.getFullYear()+3);

  //get events;
  var events = calendar.getEvents(start, end);

  //map events Array to a two-dimensional array of values;
  events = events.map(function(event){
    return [event.getTitle(),event.getDescription(),event.getStartTime(),event.getEndTime()];
  });

  //clear values;
  datarng.clear();

  //setup range;
  var rng = sh.getRange(1,1, events.length, events[0].length);

  //apply changes;
  rng.setValues(events);
}

笔记

  1. 根据 Tanaike 的评论 -如果事件是通过脚本或请求触发的,重要的是要考虑触发器(简单和可安装)以不触发(请参阅限制参考)。要启用此类功能,您必须引入轮询或与WebApp捆绑,脚本将在创建事件后调用该 WebApp(请参阅下面的捆绑示例)。
  2. 您的解决方案更适合反向流程:在电子表格中编辑 -> 在日历中编辑(如果您修改它以在日历上执行操作而不是更新电子表格,ofc)。
  3. 使用Date内置对象的方法,如getFullYear()(参见其他方法的参考),使您的代码更灵活、更易于理解。顺便说一句,我会将“一天中的毫秒”数据存储为常数(86400000)。
  4. 永远不要在循环中使用getRange(),getValue()setValue()类似的方法(并且通常尽可能少地调用它们) - 它们是 I/O 方法,因此速度很慢(您可以通过尝试在循环中写入超过 200 行来亲眼看看)。在开始时获取所需的范围/值,执行修改并批量写入(例如使用setValues()方法)。

参考

  1. EventUpdated事件参考
  2. 日历增量同步指南
  3. Date内置对象引用
  4. setValues()方法参考
  5. 在 Google Apps Script 中使用批处理操作;
  6. 可安装简单的触发限制;

WebApp 捆绑

第 0 部分 - 先决条件

如果您想通过脚本执行创建/更新/删除日历事件,您可以将目标脚本与一个简单的 WebApp 捆绑在一起。您需要确保:

  1. WebApp 部署的访问权限设置为 as anyone, even anonymous(强烈建议引入某种形式的请求认证);
  2. WebApp 代码有一个函数,名为doPost接受事件对象(通常命名为e,但由您决定)作为单个参数。

第 1 部分 - 构建 WebApp

此构建假定所有修改都在 WebApp 中进行,但是您可以,例如,返回回调名称以在成功请求时运行并在调用脚本中处理更新。由于calendarId在上面的回调中只使用了事件对象的属性,我们可以向它传递一个只有这个属性集的自定义对象:

/**
 * Callback for POST requests (always called "doPost");
 * @param {Object} e event object;
 * @return {Object} TextOutput;
 */
function doPost(e) {
  //access request params;
  var body = JSON.parse(e.postData.contents);

  //access calendar id;
  var calendarId = body.calendar;

  if(calendarId) {
    updateSpreadsheet({calendarId:calendarId}); //callback;
    return ContentService.createTextOutput('Success');
  }else {
    return ContentService.createTextOutput('Invalid request');
  }
}

第 2 部分 - 示例调用脚本

此构建假定调用脚本和 WebApp 是同一个脚本项目(因此它的 Url 可以通过 访问ScriptApp.getService().getUrl(),否则粘贴在 WebApp 部署期间提供给您的那个)。构建需要熟悉UrlFetchApp(参见参考资料)。

/**
 * Creates event;
 */
function createEvent() {
  var calendar = CalendarApp.getCalendarById('your calendar id here');

  //modify whatever you need to (this build creates a simple event);
  calendar.createEvent('TEST AUTO', new Date(), new Date()); 

  //construct request parameters;
  var params = {
    method: 'post',
    contentType: 'application/json',
    muteHttpExceptions: true,
    payload: JSON.stringify({
      calendar: calendar.getId()
    })
  };

  //send request and handle result;
  var updated = UrlFetchApp.fetch(ScriptApp.getService().getUrl(),params);
  Logger.log(updated); //should log "Success";
}

推荐阅读