Multiple calendar ID's in a google script - google-apps-script

New to programming and I have been hitting my head against the wall when trying to add multiple calendar ID's to the script below.
I need it to iterate through the rows and if the event hasn't been added to the calendar yet, add it to mine and to others' calendars, as the sheet gets updated.
function addToCal() {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getSheetByName("ProductionSchedule"),
range = sheet.getActiveRange(),
row = range.getRow(),
data = sheet.getRange(row, 1, 1, 26).getValues(),
date = data[0][6];
if (date =='') return;
var today = new Date(),
startDate = new Date(today.setMonth(today.getMonth()-1)),
endDate = new Date(today.setMonth(today.getMonth()+6)),
calId = 'calendarID',
cal = CalendarApp.getCalendarById(calId),
events = cal.getEvents(startDate, endDate),
titles = [];
for (var i = 0, len = events.length; i < len; i++)
titles.push(events[i].getTitle());
var item = ('Produção de' + ' ' + data[0][3]),
qtd = ('Qtd (und): ' + data[0][5]),
local = ('Local de Produção: ' + data[0][4]);
var index = titles.indexOf(item),
ok = 1;
if (index > -1)
{
var eventDate = events[index].getAllDayStartDate();
if (eventDate.getTime() == date.getTime()) var ok = 0;
else events[index].deleteEvent();
}
if (ok)
cal.createAllDayEvent(item, date, {description: qtd, location: local})
.removeAllReminders();
}
Currently, it sets the events to my calendar containing Item Description as the event title, Product name, qty and Production Location in the description field. I would need the same information to be added to others' calendars.
Besides, this can't mark me as Busy and the event doesn't need to be an All Day event.
Any help is appreciated.
Cheers,

In order to repeat the calendar interactions for multiple calendars, you need to create an array of calendar IDs and loop through them.
One approach would be:
var CALENDER_IDS = [
"calendarID1",
"calendarID2",
"calendarID3",
]
func addToCal() {
... spreadsheet data extraction and date calculations ...
for (var i = 0, clen = CALENDER_IDS.length; i < clen; i++) {
var cal = CalendarApp.getCalendarById(CALENDER_IDS[i]);
... calendar interactions ...
}
}
If you use the above code, make sure to update the counter variable in the title loop (i.e. they both can't be i). Common practice is to make inner loops use j, k, etc.

Related

API call to calendar.events.import failed with error: Invalid iCalUID value [duplicate]

I'm building a script to retrieve certain events from my calendar and send an email for each qualifying event with a hyperlink to the event. For that I need event id, not icalUID. How do I get that? Here is my code (actual IDs and names were removed):
function GetFamilyEvents () {
//Gets all events that start/end/or span within next 30 days
var FamilyCalendar = CalendarApp.getCalendarById("someID#group.calendar.google.com");
var CurrentDate = new Date(); //Gets current date
var RangeEnd = new Date(CurrentDate.getTime() + 720 * 60 * 60 * 1000); //Adds 30 days in milliseconds to the current date
var FamilyEvents = FamilyCalendar.getEvents(CurrentDate,RangeEnd); //returns events that start, end, or encompass wihtin 30 days starting from today; Time range is Current Date to Range End
for(var i = 0; i<FamilyEvents.length; i++){
var EventTitle = FamilyEvents[i].getTitle();
var EventCreatedDate = FamilyEvents[i].getDateCreated();
var EventStartDate = FamilyEvents[i].getStartTime();
var EventEndDate = FamilyEvents[i].getEndTime();
var EventCreator = FamilyEvents[i].getCreators(); //Gets the creator of the event to email notificaiton to
var EventID = FamilyEvents[i].getID();
var CalendarID = FamilyCalendar.getId();
//Check if an event was created today AND does not have our names or "FYI" in its title
if(EventCreatedDate.valueOf() <= CurrentDate.valueOf() && EventTitle.indexOf('Name1')<0 && EventTitle.indexOf('Name2')<0 && EventTitle.indexOf('Name3')<0 && EventTitle.indexOf('Name4')<0 && EventTitle.indexOf('Name5')<0 && EventTitle.indexOf('FYI')<0)
{
//Creates variables for the HTML body of the email notification. The same variables are referenced in the body of the HTML template.
var EmailMessage = HtmlService.createTemplateFromFile("EmailMessage"); //"EmailMessage" is the name of the HTML file in this script.
EmailMessage.recepient = EventCreator;
EmailMessage.eventTitle = EventTitle;
EmailMessage.eventStartDate = EventStartDate;
EmailMessage.eventEndDate = EventEndDate;
EmailMessage.calendarID = CalendarID;
EmailMessage.eventID = EventID;
};
Thank you
From For that I need event id, not icalUID., when you want to retrieve the event ID, how about the following modification?
From:
var EventID = FamilyEvents[i].getID();
To:
var EventID = FamilyEvents[i].getId().split("#")[0];
Id of getId() is required to be modifieid.
getId() returns the value like ####google.com which is iCalUID. The event ID is retrieved from this as ###.
Reference:
getId()
Added:
From your replying,
what I meant was that my original code and your modifications give the same result: 2C18CFDB-E6B6-4653-AB65-21C990969103 - this is what I get for both options.
In this case, how about using Calendar API? By this, both the event ID and also the hyperlink of the event can be retrieved. When this is reflected in your script, it becomes as follows.
Sample script:
Before you use this, please enable Calendar API at Advanced Google services. And, please set your calendar ID.
function sample() {
var calendarId = "someID#group.calendar.google.com"; // Please set your calendar ID
//Gets all events that start/end/or span within next 30 days
var CurrentDate = new Date(); //Gets current date
var RangeEnd = new Date(CurrentDate.getTime() + 720 * 60 * 60 * 1000); //Adds 30 days in milliseconds to the current date
var items = Calendar.Events.list(calendarId, { timeMin: CurrentDate.toISOString(), timeMax: RangeEnd.toISOString(), maxResults: 2500 }).items;
items.forEach(e => {
var EventTitle = e.summary; // FamilyEvents[i].getTitle();
var EventCreatedDate = new Date(e.created); // FamilyEvents[i].getDateCreated();
var EventStartDate = new Date(e.start.dateTime || e.start.date);// FamilyEvents[i].getStartTime();
var EventEndDate = new Date(e.end.dateTime || e.end.date); // FamilyEvents[i].getEndTime();
var EventCreator = e.creator.email; // FamilyEvents[i].getCreators(); //Gets the creator of the event to email notificaiton to
var EventID = e.id; // FamilyEvents[i].getID();
var CalendarID = calendarId; // FamilyCalendar.getId();
var eventUrl = e.htmlLink; // If you want to retrieve the hyperlink of the event, you can use this.
//Check if an event was created today AND does not have our names or "FYI" in its title
if (EventCreatedDate.valueOf() <= CurrentDate.valueOf() && EventTitle.indexOf('Name1') < 0 && EventTitle.indexOf('Name2') < 0 && EventTitle.indexOf('Name3') < 0 && EventTitle.indexOf('Name4') < 0 && EventTitle.indexOf('Name5') < 0 && EventTitle.indexOf('FYI') < 0) {
//Creates variables for the HTML body of the email notification. The same variables are referenced in the body of the HTML template.
var EmailMessage = HtmlService.createTemplateFromFile("EmailMessage"); //"EmailMessage" is the name of the HTML file in this script.
EmailMessage.recepient = EventCreator;
EmailMessage.eventTitle = EventTitle;
EmailMessage.eventStartDate = EventStartDate;
EmailMessage.eventEndDate = EventEndDate;
EmailMessage.calendarID = CalendarID;
EmailMessage.eventID = EventID;
// do something
};
});
}
In this sample script, eventUrl is the hyperlink of the event.
The Google Event ID can be determined if you have both the iCalUID and the corresponding CalendarID that event belongs to. And once you have the Event ID, assembling a URL for the event is a piece of cake.
Step 1
Grab the first part of the iCalUID.. up to but not including the # sign.
Step 2
Concatenate the string from step 1 with a the CalendarID separated by a single space.
Step 3
Use the built-in Utilities class to encode the string from step 2 to a web-safe base64 string.
Step 4
Assemble your url
let str = EventID.split('#')[0].toString();
let str2 = str + ' ' + CalendarID;
let eid = Utilities.base64EncodeWebSafe(str2, Utilities.Charset.UTF_8);
let url = 'https://www.google.com/calendar/event?eid=' + eid;
We can simplify all that into a one liner. Add it to your for loop after the CalendarID variable declaration.
let url = 'https://www.google.com/calendar/event?eid=' + Utilities.base64EncodeWebSafe(EventID.split('#')[0].toString() + ' ' + CalendarID, Utilities.Charset.UTF_8);

Google Calendar event id, not icalUID

I'm building a script to retrieve certain events from my calendar and send an email for each qualifying event with a hyperlink to the event. For that I need event id, not icalUID. How do I get that? Here is my code (actual IDs and names were removed):
function GetFamilyEvents () {
//Gets all events that start/end/or span within next 30 days
var FamilyCalendar = CalendarApp.getCalendarById("someID#group.calendar.google.com");
var CurrentDate = new Date(); //Gets current date
var RangeEnd = new Date(CurrentDate.getTime() + 720 * 60 * 60 * 1000); //Adds 30 days in milliseconds to the current date
var FamilyEvents = FamilyCalendar.getEvents(CurrentDate,RangeEnd); //returns events that start, end, or encompass wihtin 30 days starting from today; Time range is Current Date to Range End
for(var i = 0; i<FamilyEvents.length; i++){
var EventTitle = FamilyEvents[i].getTitle();
var EventCreatedDate = FamilyEvents[i].getDateCreated();
var EventStartDate = FamilyEvents[i].getStartTime();
var EventEndDate = FamilyEvents[i].getEndTime();
var EventCreator = FamilyEvents[i].getCreators(); //Gets the creator of the event to email notificaiton to
var EventID = FamilyEvents[i].getID();
var CalendarID = FamilyCalendar.getId();
//Check if an event was created today AND does not have our names or "FYI" in its title
if(EventCreatedDate.valueOf() <= CurrentDate.valueOf() && EventTitle.indexOf('Name1')<0 && EventTitle.indexOf('Name2')<0 && EventTitle.indexOf('Name3')<0 && EventTitle.indexOf('Name4')<0 && EventTitle.indexOf('Name5')<0 && EventTitle.indexOf('FYI')<0)
{
//Creates variables for the HTML body of the email notification. The same variables are referenced in the body of the HTML template.
var EmailMessage = HtmlService.createTemplateFromFile("EmailMessage"); //"EmailMessage" is the name of the HTML file in this script.
EmailMessage.recepient = EventCreator;
EmailMessage.eventTitle = EventTitle;
EmailMessage.eventStartDate = EventStartDate;
EmailMessage.eventEndDate = EventEndDate;
EmailMessage.calendarID = CalendarID;
EmailMessage.eventID = EventID;
};
Thank you
From For that I need event id, not icalUID., when you want to retrieve the event ID, how about the following modification?
From:
var EventID = FamilyEvents[i].getID();
To:
var EventID = FamilyEvents[i].getId().split("#")[0];
Id of getId() is required to be modifieid.
getId() returns the value like ####google.com which is iCalUID. The event ID is retrieved from this as ###.
Reference:
getId()
Added:
From your replying,
what I meant was that my original code and your modifications give the same result: 2C18CFDB-E6B6-4653-AB65-21C990969103 - this is what I get for both options.
In this case, how about using Calendar API? By this, both the event ID and also the hyperlink of the event can be retrieved. When this is reflected in your script, it becomes as follows.
Sample script:
Before you use this, please enable Calendar API at Advanced Google services. And, please set your calendar ID.
function sample() {
var calendarId = "someID#group.calendar.google.com"; // Please set your calendar ID
//Gets all events that start/end/or span within next 30 days
var CurrentDate = new Date(); //Gets current date
var RangeEnd = new Date(CurrentDate.getTime() + 720 * 60 * 60 * 1000); //Adds 30 days in milliseconds to the current date
var items = Calendar.Events.list(calendarId, { timeMin: CurrentDate.toISOString(), timeMax: RangeEnd.toISOString(), maxResults: 2500 }).items;
items.forEach(e => {
var EventTitle = e.summary; // FamilyEvents[i].getTitle();
var EventCreatedDate = new Date(e.created); // FamilyEvents[i].getDateCreated();
var EventStartDate = new Date(e.start.dateTime || e.start.date);// FamilyEvents[i].getStartTime();
var EventEndDate = new Date(e.end.dateTime || e.end.date); // FamilyEvents[i].getEndTime();
var EventCreator = e.creator.email; // FamilyEvents[i].getCreators(); //Gets the creator of the event to email notificaiton to
var EventID = e.id; // FamilyEvents[i].getID();
var CalendarID = calendarId; // FamilyCalendar.getId();
var eventUrl = e.htmlLink; // If you want to retrieve the hyperlink of the event, you can use this.
//Check if an event was created today AND does not have our names or "FYI" in its title
if (EventCreatedDate.valueOf() <= CurrentDate.valueOf() && EventTitle.indexOf('Name1') < 0 && EventTitle.indexOf('Name2') < 0 && EventTitle.indexOf('Name3') < 0 && EventTitle.indexOf('Name4') < 0 && EventTitle.indexOf('Name5') < 0 && EventTitle.indexOf('FYI') < 0) {
//Creates variables for the HTML body of the email notification. The same variables are referenced in the body of the HTML template.
var EmailMessage = HtmlService.createTemplateFromFile("EmailMessage"); //"EmailMessage" is the name of the HTML file in this script.
EmailMessage.recepient = EventCreator;
EmailMessage.eventTitle = EventTitle;
EmailMessage.eventStartDate = EventStartDate;
EmailMessage.eventEndDate = EventEndDate;
EmailMessage.calendarID = CalendarID;
EmailMessage.eventID = EventID;
// do something
};
});
}
In this sample script, eventUrl is the hyperlink of the event.
The Google Event ID can be determined if you have both the iCalUID and the corresponding CalendarID that event belongs to. And once you have the Event ID, assembling a URL for the event is a piece of cake.
Step 1
Grab the first part of the iCalUID.. up to but not including the # sign.
Step 2
Concatenate the string from step 1 with a the CalendarID separated by a single space.
Step 3
Use the built-in Utilities class to encode the string from step 2 to a web-safe base64 string.
Step 4
Assemble your url
let str = EventID.split('#')[0].toString();
let str2 = str + ' ' + CalendarID;
let eid = Utilities.base64EncodeWebSafe(str2, Utilities.Charset.UTF_8);
let url = 'https://www.google.com/calendar/event?eid=' + eid;
We can simplify all that into a one liner. Add it to your for loop after the CalendarID variable declaration.
let url = 'https://www.google.com/calendar/event?eid=' + Utilities.base64EncodeWebSafe(EventID.split('#')[0].toString() + ' ' + CalendarID, Utilities.Charset.UTF_8);

Check if contact exists under google contacts with "ContactsApp.getContact"

I'm noob regarding scripting so keep that in mind. :-)
I want my script to read from google sheet and and check if that contact exist under google contacts and if not to create one.
Contacts are checked by email and have label "Client". I can't get if statement to confirm if contact exist or not. If i remove If for checking contacts it will create contact for every single entry so i think that that part is fine, but i need to fix part how to check if contact already exists so it wouldn't create duplicated entry.
function addClinet() {
var ss = SpreadsheetApp.openById('XXXX');
var sheetNew = ss.getSheetByName('NewClient');
var Avals = sheetNew.getRange('B1:B').getValues();
var lastRow = Avals.filter(String).length;
for (var i = 2 ; i <= lastRow; i++){
var nameID = sheetNew.getRange(i, 2).getValue();
var emailID = sheetNew.getRange(i, 8).getValue();
var mobID = sheetNew.getRange(i, 9).getValue();
var firstName = nameID.split(' ').slice(0, -1).join(' ');
var lastName = nameID.split(' ').slice(-1).join(' ');
var regex = new RegExp (/^\w/);
var firstChar = regex.exec(mobID);
var contacts = ContactsApp.getContact(emailID);
if (contacts == null){
if (firstChar == 8){
var mobID = 'xxx' + mobID;
}
var contact = ContactsApp.createContact(firstName,lastName, emailID);
var contacts = ContactsApp.getContact(emailID);
contact.addPhone(ContactsApp.Field.WORK_PHONE, mobID);
var group = ContactsApp.getContactGroup("Clients");
group.addContact(contact);
}
}
}
Thx
I wouldn't use the ContactsApp.getContact([email]) function -- For whatever reason Google Apps Script's contacts search by email is excruciatingly slow. Since it sounds like you have a number of contacts that you are sorting through at any given time, I would recommend you use the same -- instead of searching for the email address through Google Apps Script (this takes about 16-20 seconds PER CONTACT)
Using the following function you will be able to create one large JSON object of all of your contacts, with their email addresses as the key so you can quickly test whether an email address is present in your contacts (this takes about 11 seconds for around 5000 contacts:
function emailsasJSON() {
var emailjson = {}
var myContacts = ContactsApp.getContactGroup('Clients').getContacts();
for (var i = 0; i < myContacts.length; i++) {
var emails = myContacts[i].getEmails();
var phonesobj = myContacts[i].getPhones();
var phones = {}
for (var j = 0; j < phonesobj.length; j++) {
phones[phonesobj[j].getPhoneNumber().replace(/[_)(\s.-]/g,'')] = 1;
}
for (var j = 0; j < emails.length; j++) {
emailjson[emails[j].getAddress().toLowerCase()] = {id: myContacts[i].getId(), phones: phones};
}
}
Logger.log(JSON.stringify(emailjson))
return emailjson;
}
Using the emailjson object you can compare each of your contacts MUCH faster -- It will create this in about 10 seconds -- we will use this later.
Secondly, there are some things in your code that I would clean up -- it looks to me like you have a sheet with the name in column B, email in column H, and mobile number in column I.
Instead of collecting all of those values individually per cell (takes a long time), you should collect the entire data set as an array and then work with it that way:
function addClinet() {
var ss = SpreadsheetApp.openById('XXXX');
var sheetNew = ss.getSheetByName('NewClient');
var clientsgroup = ContactsApp.getContactGroup('Clients')
//this is where we will insert the function from above to get the emailjson obj
var emailjson = emailsasJSON()
var contactarray = sheetNew.getDataRange().getValues();
for (var i = 1 ; i < contactarray.length; i++){
var name = contactarray[i][1]
var email = contactarray[i][7]
var phone = contactarray[i][8]
if(emailjson[email.toLowerCase()].id) { //check if email exists
if(!emailjson[email.toLowerCase()]['phones'][phone.replace(/[_)(\s.-]/g,'')]) { //if email exists but phone doesn't, add phone
ContactsApp.getContactById(emailjson[email.toLowerCase()].id).addPhone(ContactsApp.Field.MOBILE_PHONE, phone)
emailjson[email.toLowerCase()]['phones'][phone.replace(/[_)(\s.-]/g,'')] = 1; //add it to the emailjson object in case there are more iterations of this contact in the sheet
}
} else { //add new contact if it doesn't exist
var newcontact = ContactsApp.createContact(name.split(' ')[0],name.split(' ')[1], email)
newcontact.addPhone(ContactsApp.Field.MOBILE_PHONE, phone)
emailjson[email.toLowerCase()]['id'] = newcontact.getId();
emailjson[email.toLowerCase()]['phones'][phone.toString().replace(/[_)(\s.-]/g,'')] = 1;
clientsgroup.addContact(newcontact)
}
}
}
I don't have your datasheet to error check this but this should speed up your function by a considerable amount. Let me know if it throws any errors or, if you could give me an example sheet, I could test it.
Lastly, I imagine that this isn't a client list that you consistently update, so I would take them off of this sheet and move them elsewhere, although it would take a considerable number of contacts on the list to bog this function down.

Converting Dataset from 'Wide' to 'Long' in Google Apps Script for Google Sheet

I need some help generating a google script AND/or Formula for this one..
In the attached gsheet below, I have the following raw dataset...
For Phase 1, I need to convert this 'wide' format to a 'long' format whereby new columns are created for each attribute in 'Data Type' and 'T1' and 'T2' are condensed in their own column called 'Time'. Please see below...
For Phase 2, I need to join all info across each row but split by 'Time'. Please see below...
Finally for Phase 3, I need to create one additional step where each is split by Col A. Please see below...
I have tried to achieve the reshaping of the data via 'QUERY'and 'Transpose' but can't seem to do it. If anyone has a custom build function that addresses this very common task, I would very much appreciate your help on this one!
Dataset is below...
https://docs.google.com/spreadsheets/d/1Ujxki1wmaLmkBgZQHI-OTwSubKdlN5mvLDdGWhCBn3E/edit?usp=sharing
Thanks.
How about this sample script? I'm interested in the situation of your issue. So I challenged this. This is also for my study. In my answer, I tried to solve your question using GAS. I think that there are several answers for your situation. So please think of this as one of them.
In this sample script, the values for "Phase 1", "Phase 2" and "Phase 3" are created every 1 cycle of the data. From your question and sample spreadsheet, I thought that the cycle of data is 5. Then, the created values are imported the 3 sheets.
Sample script :
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var rawData = ss.getSheetByName("Raw Data").getDataRange().getValues();
var header = rawData[0];
var delimiter = "| "; // Please input delimiter.
var cycle = 5; // From your question, I thought the cycle of data is 5.
var phase1 = [];
var phase2 = [];
var phase3 = [];
rawData.shift();
for (var i = 0; i < rawData.length; i += cycle) {
var temp1 = [];
var temp2 = [];
for (var j = i; j < i + cycle; j++) {
temp1.push([rawData[j][0], rawData[j][1]]);
temp2.push([rawData[j][3], rawData[j][4]]);
}
var converted = temp2[0].map(function(_, i){return temp2.map(function(f){return f[i]})}) // Transpose
.map(function(e, i){return temp1[i].concat(e).concat(header[i + 3])}); // Add T1 and T2
// Create value for phase1.
Array.prototype.push.apply(phase1, converted);
// Create value for phase2.
phase2.push([converted[0].slice(0, 7).join(delimiter), converted[1].slice(0, 7).join(delimiter)]);
// Create value for phase3.
phase3.push([converted[0][0], header[3], header[4]]);
phase3.push(["", converted[0].slice(1, 7).join(delimiter), converted[1].slice(1, 7).join(delimiter)]);
phase3.push(["", "", ""]);
}
// If you want to change the sheet name, please modify this part.
var all = [
[ss.getSheetByName("Phase 1"), phase1],
[ss.getSheetByName("Phase 2"), phase2],
[ss.getSheetByName("Phase 3(Desired Final Output)"), phase3]
];
all.forEach(function(e) {
// Import values to 3 sheets.
e[0].getRange(e[0].getLastRow() + 1, 1, e[1].length, e[1][0].length).setValues(e[1]);
});
}
If I misunderstand your question, I'm sorry.
Edit
When the modified script is run, all converted values are overwrote for 3 sheets of phase 1, phase 2 and phase 3.
The name of Data Melt can't be used for the function name. So DataMelt was used for it.
For example, =DataMelt('Raw Data'!A2:E6) is put to a cell, the converted data for phase 1 is imported.
In this function, the data that 5 rows are 1 cycle can be used.
Modified script
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var rawData = ss.getSheetByName("Raw Data").getDataRange().getValues();
var header = rawData[0];
var delimiter = "| "; // Please input delimiter.
var cycle = 5; // From your question, I thought the cycle of data is 5.
var phase1 = [];
var phase2 = [];
var phase3 = [];
rawData.shift();
for (var i = 0; i < rawData.length; i += cycle) {
var temp1 = [];
var temp2 = [];
for (var j = i; j < i + cycle; j++) {
temp1.push([rawData[j][0], rawData[j][1]]);
temp2.push([rawData[j][3], rawData[j][4]]);
}
var converted = temp2[0].map(function(_, i){return temp2.map(function(f){return f[i]})}) // Transpose
.map(function(e, i){return temp1[i].concat(e).concat(header[i + 3])}); // Add T1 and T2
// Create value for phase1.
Array.prototype.push.apply(phase1, converted);
// Create value for phase2.
phase2.push([converted[0].slice(0, 7).join(delimiter), converted[1].slice(0, 7).join(delimiter)]);
// Create value for phase3.
phase3.push([converted[0][0], header[3], header[4]]);
phase3.push(["", converted[0].slice(1, 7).join(delimiter), converted[1].slice(1, 7).join(delimiter)]);
phase3.push(["", "", ""]);
}
phase1.unshift(["Col A", "Col B", "Catalogue", "Display", "Equivalent Single Price", "In-Store_Shopper", "Mechanic", "Time"]);
phase2.unshift(["T1", "T2"]);
var all = [
[ss.getSheetByName("Phase 1"), phase1],
[ss.getSheetByName("Phase 2"), phase2],
[ss.getSheetByName("Phase 3(Desired Final Output)"), phase3]
];
all.forEach(function(e) {
// Import values to 3 sheets.
e[0].getRange(1, 1, e[1].length, e[1][0].length).setValues(e[1]);
});
}
// Added new function
function DataMelt(e) {
var e = [["Chalk","A0C-Len Superior Kids TP 80gm","Catalogue","No","Yes"],["Chalk","A0C-Len Superior Kids TP 80gm","Display","Shelf","GE"],["Chalk","A0C-Len Superior Kids TP 80gm","Equivalent Single Price",2.49,2.49],["Chalk","A0C-Len Superior Kids TP 80gm","In-Store_Shopper","",""],["Chalk","A0C-Len Superior Kids TP 80gm","Mechanic","LDLP","Off"]];
var rawData = e;
var header = ["Col A", "Col B", "Data Type", "T1", "T2"];
var cycle = 5; // From your question, I thought the cycle of data is 5.
var phase1 = [];
var temp1 = [];
var temp2 = [];
for (var j = 0; j < cycle; j++) {
temp1.push([rawData[j][0], rawData[j][1]]);
temp2.push([rawData[j][3], rawData[j][4]]);
}
var converted = temp2[0].map(function(_, i){return temp2.map(function(f){return f[i]})}) // Transpose
.map(function(e, i){return temp1[i].concat(e).concat(header[i + 3])}); // Add T1 and T2
// Create value for phase1.
Array.prototype.push.apply(phase1, converted);
return phase1;
}

Google Apps Script: Submit data into specified column

I am trying to find a script, or begin writing one, that takes a simple Google Form with a drop-down list of names (i.e. Tom, Jane) and a text area, and inputs both the date and the text into columns based on the selected name (i.e. Tom Date, Tom Comment). This is so I can make a quick entry feedback form for leaving individualized, date-based feedback for students, which they can then access later.
I looked through the GAS documentation and looked for examples, but as I am a novice, I really didn't know where to begin.
Any ideas on how to do this?
I think I did something similar but mine is for admins to observe teachers. I'm just learning as well, so I'm sure there are better ways to do this but it works. I definitely should have broken it up into more functions.
My form has a trigger to fire the onClose() when submitted. onClose() produces a Google Doc by reading the spreadsheet containing the form data in a nice format that the observer can then edit and share with the teacher. I wanted the Google Doc produced to have the name of the teacher being observed in the file name and I wanted it shared with the admin who did the observing.
The fact that some of the fields are dropdowns doesn't matter, it is just an itemResponse from the list of all responses.
function onClose()
{
var form = FormApp.openById(' whatever your form id is');
//the spreadsheet of the form responses
var formResponses = form.getResponses();
var d = new Date();
var currentTime = d.toLocaleTimeString();
var date = d.toLocaleDateString();
//Need to get the name of the teacher being observed
var formResponse = formResponses[formResponses.length-1];
var itemResponses = formResponse.getItemResponses();
var itemResponse = itemResponses[0]; //the teacher name dropdown box
var teacherName = itemResponse.getResponse() + '-' + itemResponses[1].getResponse();
//create the new document
var fileName = 'Observation-'+ teacherName + '-' + date + '-' + currentTime;
var doc = DocumentApp.create(fileName);
var activeDoc = DocumentApp.getActiveDocument();
var files = DriveApp.getFilesByName(fileName);
while (files.hasNext()) {
var file = files.next();
if (file.getName().equals(fileName))
{
//this is the last item on my form the name of the observer
var itemResponse21 = itemResponses[21];
var observer = itemResponse21.getResponse();
// Logger.log('Person to share with is ' + observer);
// share this google doc with the observer
file.addEditor(observer);
}
}
//ommittd a bunch of styles
//This would get all forms submitted, but I only need the last one
// so I just set the loop to get the last form submitted.
//leaving for loop just so I remember I can go through all forms again
//if I want to.
for (var i = formResponses.length-1; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
//get the individual responses within the form.addCheckboxItem()
for (var j = 0; j < itemResponses.length; j++) {
//pull the first item out again (even though I did for file name)
var itemResponse = itemResponses[j]; //teacher name from a dropbox
var itemResponse2 = itemResponses[j+1]; //date
var itemResponse3 = itemResponses[j+2]; //time
if (j == 0) //the first field on the form
{
//put the headings in
par3 = doc.appendParagraph(' SCHOOL NAME');
par3 = doc.appendParagraph('WALK IN OBSERVATION');
par3 = doc.appendParagraph('2013-2014');
//THIS is the teacher being observed and the date and time --- all on same line
var headingLine = itemResponse.getItem().getTitle() + '\t\t' + itemResponse2.getItem().getTitle() + ' / ' + itemResponse3.getItem().getTitle();
par1 = doc.appendParagraph(headingLine);
var answerLine = itemResponse.getResponse() + '\t\t\t\t\t' + itemResponse2.getResponse() + ' / ' + itemResponse3.getResponse();
par2 = doc.appendParagraph(answerLine);
j++; //do this to skip over date and time
j++;
} //end of j = 0;
else
// then I have a bunch of if statements for some of the
// specific fields I need to do something special with.
// After the last if, I just have an else to handle all other
// form responses that I don't do anything special for other than display.
//my last else is:
else
//THIS ELSE IS HANDLING ALL NON CHECK BOXES AND JUST DISPLAYING THE TITLE IN BOLD FONT, THE COMMENTS IN REGULAR FONT
{
par1 = doc.appendParagraph(itemResponse.getItem().getTitle());
par1.setAttributes(style);
par2 = doc.appendParagraph( itemResponse.getResponse());
par2.setAttributes(style);
} //END OF ELSE
} //end of for going through each cell in a row of the repsonses
} //end of for going through each row -- only had it set to do the very last row