Update calendar from google spreadsheet - google-apps-script

I would like to update my calendar from a spreadsheet:
I tried the following:
function caltest1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var calId = "TestCalendar";
var cal = CalendarApp.getCalendarById(calId);
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var desc = row[1]; // Second column
var tstart = row[2];
var tstop = row[3];
var loc = row[4];
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
}
}
However, I get the following error:
TypeError: Cannot call method "createEvent" of null
The following spreadsheet is used:
Link to spreadsheet
Any suggestions, what I am doing wrong?
I appreciate your replies!

Short answer: You are passing the calendar's name to getCalendarById() so it is returning null. Change "TestCalendar" to the ID of the calendar or use getCalendarsByName().
I will walk you through this the way I read it so you can see one way to debug this.
This error is telling you that your cal variable is null on the last line where you call cal.createEvent( ... ). This means that your earlier statement var cal = CalendarApp.getCalendarById(calId); is returning null. Googling the Google Calendar API for this function I see that you are using the correct syntax for getCalendarId() but the string argument you are passing appears to be the calendar's name and not the ID.

Related

How do I resolve this ReferenceError: "tStart" is not defined. (line 55, file "Code")?

I am trying to create calendar events from data in google sheets and each time I run the code I get ReferenceError: "tStart" is not defined. (line 55, file "Code"). Please see the code below. I'd be grateful for any assistance.
function listUpcomingEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow(); // Number of rows to process
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows-1, numColumns);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName(
"admin#someaddress.co.uk" )[0];
for (i in data) {
var row = data[i];
var title = row[8]; // First column
var tstart = row[9]; // Second column
var tstop = row[10];
Logger.log(tstop);
var desc = row[1];
var loc = row[4];
//var cmmail = row[6];
//var leamail = row[7];
cal.createEvent(title, new Date(tStart), new Date(tStop),{description:desc,location:loc});
}
}
I was expecting this to pick up the active spreadsheet and identify the dates in column J and add these to as new events to calendar.
JS is case sensitive, so "tstart" and "tStart" are two different variables.
You should either try changing tstart to tStart in your initial declaration, or vice-versa.

Updated Google Calendar events from Sheets

I am trying to sync a Google Calendar to a Sheet to allow me to easily mass update calendar events from within the sheet, then push all the changes back to the calendar.
I'm able to download all the events into my Sheet, specifically using this bit of code:
// Loop through all calendar events found and write them out starting on calulated ROW 2 (i+2)
for (var i=0;i<events.length;i++) {
var row=i+2;
var myformula_placeholder = '';
// Matching the "header=" entry above, this is the detailed row entry "details=", and must match the number of entries of the GetRange entry below
// NOTE: I've had problems with the getVisibility for some older events not having a value, so I've had do add in some NULL text to make sure it does not error
var details=[[events[i].getTitle(), events[i].getStartTime(), events[i].getEndTime(), events[i].getId()]];
var range=sheet.getRange(row,1,1,4);
range.setValues(details);
I'm able to create NEW events onto my calendar from the downloaded data using this code:
function caltest1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar();
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var desc = row[1]; // Second column
var tstart = row[2];
var tstop = row[3];
var loc = row[4];
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
}
}
However because it's creating a new event and not simply updating the original event, it creates duplicate events every time I push the script.
I want to find code that instead uses the event ID gathered in the first function and simply updates the existing event with the new information.
I'd prefer not to use code that deletes all calendar events then creates all the new ones.
The getEventSeriesById() method can be used. Even though the name indicates that this method is for getting a calendar event that is a series, it works for a single event.
The documentation states:
Gets the event series with the given ID. If the ID given is for a single CalendarEvent, then a CalendarEventSeries will be returned with a single event in the series.
Apps Script documentation - getEventSeriesById
function caltest1() {
var cal,desc,i,iCalId,loc,row,sheet,startRow,thisEvent,title,tstart,
tstop,;
sheet = SpreadsheetApp.getActiveSheet();
startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
cal = CalendarApp.getDefaultCalendar();
for (i in data) {
row = data[i];
title = row[0]; // First column
desc = row[1]; // Second column
tstart = row[2];
tstop = row[3];
loc = row[4];
iCalId = row[5];//Column 6 or F
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
//cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
thisEvent = cal.getEventSeriesById(iCalId);//Get a calendar event by it's ID
if (thisEvent) {
thisEvent.setDescription('Test it to determine if it works');//Edit the description
}
}
}
Note that the above code assumes that the calendar event ID is in column F, and that the function that downloaded the calendar data put the ID in column F.

Google script google sheet to calendar TypeError: Cannot find function createEvent in object Calendar. (line 18, file "Code")

I have attempted to create a google script that will create calendar events based on information within cells in google sheets. I have gotten to the point where everything is labeled and marked, but an error is occuring that states:
TypeError: Cannot find function createEvent in object Calendar. (line 18, file "Code")
Here is the code I have written:
function calInsert() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 25; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows, 9);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName( "EC Calendar" );
for (i in data) {
var row = data[i];
var title = row[1]; // First column
var tstart = row[2]; // Second column
var tstop = row[3];
var desc = row[4];
var loc = row[5];
var cmmail = row[6];
var leamail = row[7];
var event = cal.createEvent(title, new Date(tstart), new Date(tstop), {description:desc,location:loc,guests:cmmail,guests:leamail});
}
}
Any help you can provide would be appreciated.
var cal = CalendarApp.getCalendarsByName("EC Calendar");
This gives you an array of calendars with that name. Change this to:
var cal = CalendarApp.getCalendarsByName("EC Calendar")[0]; //Gets the correct calendar
This gives you the first Calendar with the name. I tried the below code:
function calInsert() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName( "calendar ID" )[0];
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var tstart = row[2]; // Second column
var tstop = row[3];
Logger.log(tstop);
var desc = row[1];
var loc = row[4];
//var cmmail = row[6];
//var leamail = row[7];
cal.createEvent(title, new Date(tstart), new Date(tstop), {description:desc,location:loc});
}
}
I am able to create event in my calendar. If needed, you can send cmmail and leamail to createEvent.

Create Google Calendar Events from Spreadsheet but prevent duplicates

I'm trying to write a script that will take data from a Google spreadsheet and create events in my Google calendar.
I managed that fine but it produced duplicates every time I ran it. So now I'm trying to prevent that by creating a column 17 in the spreadsheet with an automatically produced unique event ID for each row and then each time the script is run it will look at the event ID for each row and delete the corresponding event in the calendar before recreating it with the original data or updated data if I've changed the row.
I'm new to scripting of any kind and cobbled this together but am hitting a wall now. Can anyone help sort this out?
function CalInsert() {
var cal = CalendarApp.getDefaultCalendar();
var id = SpreadsheetApp.getActiveSheet().getRange(2,17).getValue();
if (id != 0) {
var event = cal.getEventSeriesById(id);
event.deleteEventSeries();
}
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow(); // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, sheet.getLastColumn());
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var desc = row[13]; // Second column
var tstart = row[14];
var tstop = row[15];
var event = cal.createEvent(title, tstart, tstop, {description:desc});
var eventid = event.getId();
SpreadsheetApp.getActiveSheet().getRange(2,17).setValue(eventid);
}
}
This is very similar to a question asked just two days ago, which was about synchronizing a spreadsheet of events with a calendar. It sounds like you want to consider the spreadsheet to be the master of events that it originates, which would simplify the problem considerably. The basics of what you need to do are covered in this answer. If you'd rather just modify existing code, I've got an implementation below.
I have a modified version of the code from this blog, that will modify pre-existing calendar entries to match the info in the spreadsheet. I have arranged my spreadsheet differently, and this is reflected in the code.
Date | Title | Start Time | End Time | Location | Description |
EventID
The event ID column gets filled in by the script when new events are created, and is then used in later invocations to retrieve events from the calendar, thereby avoiding duplication.
Script
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the exportEvents() function.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Export Events",
functionName : "exportEvents"
}];
sheet.addMenu("Calendar Actions", entries);
};
/**
* Export events from spreadsheet to calendar
*/
function exportEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 1; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "YOUR_CALENDAR_ID";
var cal = CalendarApp.getCalendarById(calId);
for (i=0; i<data.length; i++) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[0]); // First column
var title = row[1]; // Second column
var tstart = new Date(row[2]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[3]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var loc = row[4];
var desc = row[5];
var id = row[6]; // Sixth column == eventId
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createEvent(title, tstart, tstop, {description:desc,location:loc}).getId();
row[6] = newEvent; // Update the data array with event ID
}
else {
event.setTitle(title);
event.setDescription(desc);
event.setLocation(loc);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, tstart, tstop);
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
Delete / Recreate
In this alternative, the eventID is used to find and delete the previously existing event. After that, a new event is created with the data in the spreadsheet. This has the benefit that all values of the event can be updated, including start and stop times (see Notes below). On the other hand, any changes that were made to the original event will be lost - for instance, if other people had been invited to the event, or custom reminders were added.
To use this alternative, simply replace the matching code with this:
// Check if event already exists, delete it if it does
try {
var event = cal.getEventSeriesById(id);
event.deleteEventSeries();
row[6] = ''; // Remove event ID
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createEvent(title, tstart, tstop, {description:desc,location:loc}).getId();
row[6] = newEvent; // Update the data array with event ID
debugger;
Notes
The Documentation for getEventSeriesById wrongly states it returns null when no matching event is found, when instead it throws an exception. (nasty!) So I've enclosed it in a try / catch block just to keep on swimming.
Unfortunately, while getEventSeriesById works to retrieve an event, it returns an EventSeries object, which does not support the setTime() method. If you don't expect to change the time of events, this OK. Otherwise, you can change the Event into an EventSeries by setting the recurrence rules & times, or delete the old event and create a new one, as shown in Delete / Recreate. Issue 1154.
The spreadsheet always wins. Any event changes (in relevant fields) recorded via the Google Calendar will be overwritten by the script.
Id like to Post this for anyone who would like to use it, I have modified the script to work within a sheet I was already using. Date Format and event duplication were a couple of issues that needed to be fixed but after some testing im pretty happy with how this is working.I Use it to Book jobs and share them with my employees who are mobile and do construction type work across the city.
Next step is to pull calendar events to the spreadsheet so it can work both ways and I can use the calendar app on my phone to book jobs on the fly so if anyone has any advice im all ears, also i still need a script to insert form response data into the same sheet and add complete rows where the job numbers match keeping the existing Data intact.
`function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Export Events",
functionName : "exportEvents"
}]; sheet.addMenu("Calendar Actions", entries);
};
function parseDate(s) {
var months = {jan:0,feb:1,mar:2,apr:3,may:4,jun:5,
jul:6,aug:7,sep:8,oct:9,nov:10,dec:11};
var p = s.replace(".", "").split('-');
return new Date(p[2], months[p[1].toLowerCase()], p[0]);
}
/**
* Export events from spreadsheet to calendar
*/
function exportEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 6; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getDisplayValues();
//var calId = "Your calendar Id"; // PRODUCTION
var calId = "Your_calendar Id to test"; // TEST
var cal = CalendarApp.getCalendarById(calId);
//Logger.log(cal);
//Logger.log(data.length);
for (i=0; i<data.length; i++) {
if (i < headerRows) continue; // Skip header row(s)
if (data[i][0].length < 1) continue; // Skip if no content.
var row = data[i];
Logger.log(row);
var date = parseDate(row[0]); // First column
//Logger.log(date);
var title = row[1]; // Second column
var tstart = new Date();
var s = row[2].split(":");
tstart.setHours(s[0]);
tstart.setMinutes(s[1]);
tstart.setSeconds(s[2]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date();
var e = row[3].split(":");
tstop.setHours(e[0]);
tstop.setMinutes(e[1]);
tstop.setSeconds(e[2]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var loc = row[4];
var desc = row[5];
var id = row[6]; // Sixth column == eventId
// Check if event already exists, update it if it does
var event = null;
if (id.length > 0) {
try {
event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new
Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createEvent(title, tstart, tstop,
{description:desc,location:loc}).getId();
var r = i + 1;
var cell = sheet.getRange("G" + r);
cell.setValue(newEvent);
}
else {
Logger.log(event);
event.setTitle(title);
event.setDescription(desc);
event.setLocation(loc);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, tstart, tstop);
}
debugger;
}
}
`

How to integrate Google Spreadsheet with Google Calendar?

I've a Google spreadsheet in Google Apps. When I enter a date/time in spreadsheet, I want to create a corresponding entry in a particular Google Calendar? How can I do this?
This thread suggests some sort of scripting but complete solution is not given. And I'm using Google Apps instead of Google Docs as suggested by this thread.
Update : Found this thread helpful.
function caltest1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar();
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var desc = row[1]; // Second column
var tstart = row[2];
var tstop = row[3];
var loc = row[4];
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
}
}
Directly taken from here.