Triggering Script in google Sheets after Forms Submit - triggers

I have a working script in one of my google sheets projects, but now I want it to be triggered when I hit the submit button on a Google Form I have. Basically, the data from my Google Form gets exported to my Sheets form, but then I have a script to analyze the data entered. For some reason, it seems like it's doing nothing when the onSubmitForm() function is triggered. It's clear there's a problem because my logger test line displays for the onSubmitForm function but not for the EvaluateResults function.
The code in my Google Form is simple:
function onSubmitForm(){
Logger.log("onSubmitForm Running");
a.EvaluateResults();
}
The code in the Google Sheets is simple as well:
function EvaluateResults(){
Logger.log("evaluation running");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet_results = ss.getSheetByName("Sheet2");
var sheet_userForm = ss.getSheetByName("Form Responses 1");
sheet_results.getRange("C24").setValue((sheet_userForm.getRange("A2").getValue());
}

You should write the entire function in Google form script itself. You can collect the response from Google form as soon as the submit is hit.
function onSubmitForm(e){
Logger.log("onSubmitForm Running");
var itemResponses = e.response.getItemResponses();
var emailAddress = itemResponses[1].getResponse(); // Response of second question
Logger.log(emailAddress)
var ss = SpreadsheetApp.openById("SS ID"); // Replace with your Spreadsheet Id
var sheet_results = ss.getSheetByName("Sheet2");
sheet_results.getRange("C24").setValue(emailAddress);
}

Related

Send email to the new google form submission only

I'm new to the Google apps script. I wrote a script to send emails when there is a new submission from google forms using data and template from a spreadsheet. However, it sends an email to not just the new submission but also to all of the previous submissions. The whole script is quite long, so I only copy a short part of it. Is there any way to fix it?
Here is the link to the spreadsheet https://docs.google.com/spreadsheets/d/1fhuwEndIS3khg3W19jpQnBAaCp_MMrD_bfATrdf2-4I/edit?usp=sharing
Thank you.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calculation");
var lr = ss.getLastRow();
for (var i = 3; i<=lr;i++){
var currentEmail = ss.getRange(i, 1).getValue();
var currentName = ss.getRange(i, 3).getValue();
var currentScore1 = ss.getRange(i, 4).getValue();
MailApp.sendEmail(
currentEmail,
subjectline,
"HTML",
{ htmlBody: messageBody }
);
}
}
Instead of reading the values from the spreadsheet take advantage of the form submit event object. This event object has two properties including the form submission values, one is an Array of form submission values in the same order than the sheet columns, the other is an object having a property for each question each of them having an Array of values. Ref. https://developers.google.com/apps-script/guides/triggers/events
This shows the changes that need to done to your script:
function sendEmail(e) {
var currentEmail = e.values[0];
var currentName = e.values[2];
var currentScore1 = e.values[3];
MailApp.sendEmail(
currentEmail,
subjectline,
"HTML",
{ htmlBody: messageBody }
);
}
Note: In order to make the event object work, the function should be called by a Google Sheets form submit trigger.
Related
Event values and offset in Google spreadsheet
How to send an email only to the last Google form submission?

Google Form Responses in a Notification Email

I'm using the Form Notifications add-on in a Google Form. I've edited the Code.gs and CreatorNotification.html files and all works fine - when a Google Form is submitted I get an email. Now I'm trying to get some of the fields from that Form submission into the email. But with the edits I've added below, the email notification stops working.
In the Code.gs script I have:
function sendCreatorNotification() {
var form = FormApp.getActiveForm();
var settings = PropertiesService.getDocumentProperties();
var responseStep = settings.getProperty('responseStep');
responseStep = responseStep ? parseInt(responseStep) : 10;
function onFormSubmit(e) {
//Get information from form and set as variables
var First_Name = e.value[2];
// If the total number of form responses is an even multiple of the
// response step setting, send a notification email(s) to the form
// creator(s). For example, if the response step is 10, notifications
// will be sent when there are 10, 20, 30, etc. total form responses
// received.
if (form.getResponses().length % responseStep == 0) {
var addresses = settings.getProperty('creatorEmail').split(',');
if (MailApp.getRemainingDailyQuota() > addresses.length) {
var template = HtmlService.createTemplateFromFile('CreatorNotification');
template.summary = form.getSummaryUrl();
template.responses = form.getResponses().length;
template.title = form.getTitle();
template.responseStep = responseStep;
template.formUrl = form.getEditUrl();
template.notice = NOTICE;
template.firstname = First_Name;
var message = template.evaluate();
MailApp.sendEmail(settings.getProperty('creatorEmail'),
form.getTitle() + ': Case submission',
message.getContent(), {
name: ADDON_TITLE,
htmlBody: message.getContent()
});
}
}
}
}
In the CreatorNotification.html I have:
<p><i>Form Notifications</i> (a Google Forms add-on) has detected that the form
titled <b><?= title ?></b> has received
<?= responses ?> responses so far.</p>
<p>Summary of form responses</p>
<p>First Name:</p> <?= firstname ?>
Any direction would be appreciated.
You are trying to run two triggers. That "Add-on" code creates a trigger. The Add-on creates an "Installable" trigger. You already have one trigger set up for the form being submitted. The onFormSubmit(e) function is a "Simple" trigger. So, you have two triggers set up to run when a form is submitted. So, you created a conflict. If you look in the RESOURCES menu, under CURRENT PROJECT's TRIGGERS, you should see a trigger defined for the sendCreatorNotification() function.
Here's what you can try. You don't need a seperate onFormSubmit(e) simple trigger. The sendCreatorNotification() function, has the event object available to it. Just add e to the sendCreatorNotification() function:
sendCreatorNotification(e)
The write your code to get the value out of e.

How to fix this authorization Google Apps Script suggest box library issue?

I'm trying to add an autocomplete feature (a Ui in a popup window in a spreadsheet) in my Google Spreadsheet using this Google Apps Script suggest box library from Romain Vialard and James Ferreira's book (modified):
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "my_sheet" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 1) {
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
var dataCell0 = r.offset(0, 1);
if( dataCell0.getValue() == '' )
otherTestTunction();
}
}
}
But when I start editing column 1 of "my_sheet" and the Ui box appears, this autorization error happens (In my language it says: "you must have permission to perform this action"):
The documentation says that onEdit() trigger "They cannot access any services that require authentication as that user. For example, the Google Translate service is anonymous and can be accessed by the simple triggers. Google Calendar, Gmail, and Sites are not anonymous and the simple triggers cannot access those services."
Since I'm not using ContactsApp, I suppose that the suggest box library require authorization.
How could I set up an installable on Edit trigger that will ask for authorization? (Could you give me some code sample?)
Here is my test spreadsheet: https://docs.google.com/spreadsheet/ccc?key=0AtHEC6UUJ_rsdFBWMkhfWUQ0MEs2ck5OY1BsYjRSLXc&usp=drive_web#gid=0
Out of curiosity about what you suggested on authorizations needed by the library I made a test on a new sheet, the exact code below asks for spreadsheet access, nothing more.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
}
To handle that you just have to ask your user to run one function in your script (no matter what function) and they will get the following popup :
After this initial step your function will work as expected, ie the Ui will show up.
Beside that, I'm not sure I understand what you want to achieve is feasible, the onEdit trigger fires when the edit is done, meaning after you hit ENTER, then the value in the suggestBox is not taken into account... moreover you have to handler in the UI to do anything so I'm still wondering what do you really expect to do with this code ? (what would be ideal is an onClick event in spreadsheetApp but unfortunately it doesn't exist so far...)
But maybe I missed something obvious.
About installable onEdit that you mention also in your post, you should note that it doesn't need to be authorized by the end user since it would run as YOU, the person that creates the trigger and not the user accessing the SS , therefor accessing your own data and not the user's ones... That might be a non negligible restriction (as Zig mentioned in a comment earlier...)

setting up script to include google docs form data in email notification

I've setup a form using googledocs. I just want to have the actual data entered into the form emailed to me, as opposed to the generic response advising that the form has been completed.
I have no skill or experience with code etc, but was sure i could get this sorted. I've spent hours+hours and haven't had any luck.
My form is really basic.it has 5 fields. 4 of which are just text responses, and one multiple choice.
I found this tute online (http://www.labnol.org/internet/google-docs-email-form/20884/) which i think sums up what i'm trying to do, but have not been able to get it to work.
from this site i entered the following code:
function sendFormByEmail(e)
{
var email = "reports.mckeir#gmail.com";
var subject = "Google Docs Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
To this, i get the following response: ->
Your script, Contact Us Form Mailer, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.
The script is used by the document 100% Club.
Details:
Start Function Error Message Trigger End
12/3/12 11:06 PM sendFormByEmail TypeError: Cannot call method "toString" of undefined. (line 12) formSubmit 12/3/12 11:06 PM
Is anyone able to help shed some light on this for me? I'm guessing i'm not including some data neeeded, but i honestly have no clue.
Workaround http://www.labnol.org/internet/google-docs-email-form/20884/
You have to setup app script to forward the data as email.
I'll point to the comment above that solved it for me: https://stackoverflow.com/a/14576983/134335
I took that post a step further:
I removed the normal notification. The app script makes that generic text redundant and useless now
I modified the script to actually parse the results and build the response accordingly.
function sendFormByEmail(e)
{
var toEmail = "changeme";
var name = "";
var email = "";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Google Docs Form Submitted";
var message = "";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers) {
if (headers[i] = "Name") {
name = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Email") {
email = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Subject") {
subject = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Message") {
message = e.namedValues[headers[i]].toString();
}
}
// See https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
var mailOptions = {
name: name,
replyTo: email,
};
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(toEmail, subject, message, mailOptions);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
The script utilized in the example is extremely generic but very resilient to change because the message is built as a key/value pair of the form fields submitted.
If you use my script you'll have to tweak the for loop if statements to match your fields verbatim. You'll also want to edit the toEmail variable.
Thanks again for the question and answers. I was about to ditch Google Forms as the generic response was never enough for what I was trying to do.
Lastly, in response to the actual problem above "toString of undefined" specifically means one of the form fields was submitted as blank. If I had to guess, I would say the author only used this for forms where all the fields were required or a quick undefined check would've been put in place.
Something like the following would work:
for(var i in headers) {
var formValue = e.namedValues[headers[i]];
var formValueText = "";
if (typeof(formValue) != "undefined") {
formValueText = formValue.toString();
}
message += headers[i] + ' = '+ formvalueText + "\n\n";
}
I haven't tested this precisely but it's a pretty standard way of making sure the object is defined before trying methods like toString() that clearly won't work.
This would also explain Jon Fila's answer. The script blindly assumes all of the header rows in the response are sent by the form. If any of the fields aren't required or the spreadsheet has fields that are no longer in the form, you'll get a lot of undefined objects.
The script could've been coded better but I won't fault the author as it was clearly meant to be a proof of concept only. The fact that they mention the replyTo correction but don't give any examples on implementing it made it perfectly clear.
If this is a Google Form, do you have any extra columns in your spreadsheet that are not on the form? If you delete those extra columns then it started working for me.
You don't need to use a script. Simply go to Tools >> Notification Rules on your Google Spreadsheet. There you can change the settings to receive an email with your desired information every time the document is changed.

Google Apps Script Published Dashboard doesn't load data unless spreadsheet is open

I have a set of published dashboards that are linked to from a google site. The dashboards are all pulling data from a google spreadsheet, they are fairly basic - filterable datatables mostly. It is a pretty large spreadsheet with a lot of vlookups and a few importrange, a few filter formulas, some query formulas...there is a lot going on...often you get the "some formulas are taking a while to process message"
The dashboards work great if you have the spreadsheet open. Or if someone else has it open. But, if you close out of the spreadsheet, and wait a while, and try and run the dashboards when the spreadsheet is closed, often the dashboards don't pull in any data.
I'm suspicious that I need to allow the dashboards to wait for the data to load a little longer, or somehow open the spreadsheet in the "background" if that is possible. Any thoughts? Here's an example dashboard I have:
function doGet() {
var ss = SpreadsheetApp.openById("0Aq2VphSIvT4NdE1IRTlzV0NyWF9XZ1hsX2hXZG0xdHc");
var lastrow = ss.getSheetByName('CIC Student Aggregate').getLastRow();
var data = ss.getSheetByName('CIC Student Aggregate').getRange(1, 1, lastrow, 13);
var StudentFilter = Charts.newStringFilter()
.setFilterColumnLabel("Student Name")
.build();
var TotalsFilter = Charts.newNumberRangeFilter()
.setFilterColumnLabel("Total Interactions")
.build();
var tablechart = Charts.newTableChart()
.setDimensions(680, 550)
.setDataViewDefinition(Charts.newDataViewDefinition()
.setColumns([0,1,7,8,9,10,11,12]))
.build();
var piechart = Charts.newPieChart()
.setDimensions(330, 350)
.setDataViewDefinition(Charts.newDataViewDefinition()
.setColumns([0,12]))
.build();
var dashboard = Charts.newDashboardPanel()
.setDataTable(data)
.bind([StudentFilter,TotalsFilter], [tablechart,piechart])
.build();
var uiApp = UiApp.createApplication()
.setTitle("Interactions Totals")
.setWidth(980)
.setHeight(600);
dashboard.add(uiApp.createVerticalPanel()
.add(StudentFilter).add(TotalsFilter)
.setSpacing(1)
.add(uiApp.createHorizontalPanel()
.add(uiApp.createVerticalPanel())
.add(tablechart).add(piechart)
));
uiApp.add(dashboard);
return uiApp;
}
do you still have your problem ?
If it is the case, do you have some 'importrange' in your dashboard ?
If you read data with appscript on a range where the data is generated via importrange, it will return nothing if the spreadsheet is closed.
In fact, 'importrange' is triggered only when a user open a spreadsheet. Appscript doesn't trigger the 'importrange' on Spreadsheet opening.