I'm building a form for students to enter in and I want to Auto input their email address and I'm unsure how to do this. I'm come up with the following but I'm very new to this and may be way off. I'm unsure how to implement it and I'm getting a null response. Do I need a form question which says email ? how do I get the user's email to be recorded but in a hidden way?
function formEnterEmail(e) {
var userEmail = Session.getActiveUser().getEmail();
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
// Set the status of the new ticket to 'New'.
// Column F is the Status column
sheet.getRange(lastRow, getColIndexByName("Email")).setValue(userEmail);
function getColIndexByName(colName) {
var sheet = SpreadsheetApp.getActiveSheet();
var numColumns = sheet.getLastColumn();
var row = sheet.getRange(1, 1, 1, numColumns).getValues();
for (i in row[0]) {
var name = row[0][i];
if (name == colName) {
return parseInt(i) + 1;
}
}
return -1;
}
}
You can collect the user's email address in Google Forms only if you are using Google Apps for Business or Google Apps for Education, and then only from users in your domain. If you don't meet those requirements, then your only option is to request that users fill in the information, or to email a URL to a pre-filled-form.
This isn't really "hidden", as the live form will report that the user id is being collected.
If you're creating your form from a script, you can control the email collection feature by using Form.setCollectEmail(true). However, you can also set this up without using any code.
In the form editor, look for "Form Settings". They should appear above all the questions. Set the check boxes that require domain login, and username collection.
The spreadsheet that collects responses will automatically contain a "Username" column:
If you are building a form that you will be emailing to the students, then when you set up the form you can have it log all their email addresses for you without you having to write any script at all.
Here is a great way to get started writing a new form... go to this page:
http://www.google.com/drive/apps.html?usp=ad_search
and scroll down to the "Forms" section then click on "Create".
This should walk you through everything you will need to set up the form, and the results will be put into a spreadsheet for you, along with the students' email addresses. You can keep the resulting spreadsheet private so that you will be the only one who can view all the responses.
I hope that helps.
Related
I'm very new to writing scripts, and I've been stuck on this same script for weeks now.
I have a Google Form with a question that asks staff to list an email address if an additional person needs to be contacted when their form is submitted.
I'd like to write a script for the Form Responses Spreadsheet that will automatically send an email to the email address added to column N, when their email is added to this sheet.
I'd like the email to also include the URL link to the spreadsheet so they can reference the response. (Or even better: could the email include the data from their form submission?!)
I'd also like to have the emails come from a specific email address (will they only come from the account that is writing the script?)
I can get the script to run, but it is not successfully sending to the email address that is ADDED to the sheet, and I can't figure out how and where to add the trigger to send the email when a new email address is added to column N. It also seems to be triggering an error due to any cells where an email is NOT listed in column N.
Can someone draft a sample script for me that meets the criteria above?
Tab name: Form Responses 1
Emails in: Column N (N2:N5000)
Send email: anytime an email address is ADDED to column N (skip any blank cells)
Email text: include values added to form response/new row?
Thank you!
save the following code in the app script of the spreadsheet that contains the Form responses:
function onMyFormSubmit(e) {
let sheetName = e.range.getSheet().getName();
if(sheetName == "Form Responses 1"){
let eventVals = e.namedValues;
let emailAddress = eventVals["*Replace with email field name*"].toString();
if(emailAddress != ""){
let bodyText = "";
let keys = Object.keys(eventVals);
keys.forEach((key, index) => {
bodyText += `${key}: ${eventVals[key]}\n`;
});
let subject = "*Replace with subject of email*";
MailApp.sendEmail(emailAddress,subject,bodyText);
}
}
}
Please, raplace the text in the code between ** with the required information.
After saving the code in the App script. Please, set a trigger by cliking on the "clock" on the left pane, then click on the "+ Add Trigger" button: Image for reference
After setting the trigger, accept all permissions required by the Google.
New code based on comment "Is there any way to re-order or re-organize the order in which the Google Form fields are listed in the email that is generated?"
function onMyFormSubmit(e) {
let sheetName = e.range.getSheet().getName();
if(sheetName == "Form Responses 1"){
let eventVals = e.values;
let emailAddress = eventVals[13];
if(emailAddress != ""){
const sheet = e.range.getSheet();
const headers = sheet.getRange(1,1,1,sheet.getLastRow()).getValues();
let bodyText = "";
for (let i = 0; i < eventVals.length; i++){
bodyText += `${i+1}. ${headers[0][i]}: ${eventVals[i]}\n`;
}
let subject = "subject of the email";
MailApp.sendEmail(emailAddress,subject,bodyText);
}
}
}
This second script access the e.values instead of e.namedValues since e.values come in order as the columns of the spreadsheet, the downside of that function is that the headers are not included so it is needed to access the headers from the spreadsheet and then place things together in the for loop.
I'm trying to figure out how to do conditional statements tilizing app script in Google form with my already existing form. I have an email field which supposedly checks from a google sheet values in one column (email column). If what has been inputted into the email field exists in the Google sheet column for email, an alert prompts that the email already exists, help text will also show with a message like "email already exist". If the Ok button of the alert prompt is clicked, user can now go back into the Google form and edit their answers into the email field, and if the email address inputted does not exist in the Google sheet, nothing happens, and the user can proceed answering the form and lastly submit the form.
I have tried textvalidation but it seems text validation would only be able to answer one part of what I wanted to do with my form - show a help text. Below is my working app script:
var sheet = SpreadsheetApp.openById("IdOfMyGoogleSheet");
function validationTest() {
var data = sheet.getRange("Form Responses 1!F2:F").getValues();
var form = FormApp.openById('formID');
var item = form.getItemById(itemID)asTextItem();;
var textValidation = FormApp.createTextValidation()
.setHelpText("Email already exist")
.requireTextContainsPattern(data)
.build();
item.setValidation(textValidation);
}
Thanks in advance!
The first this to note is that a pattern is a regular expression. You also need to use requireTextDoesNotMatchPattern instead of requireTextContainsPattern. Here is what I've tested:
function setPattern() {
// Get the firm item
const form = FormApp.openById('form ID')
const item = form.getItemById('itemID').asTextItem()
// Get the list of values
const spreadsheet = SpreadsheetApp.openById('Spreadsheet ID')
const sheet = spreadsheet.getSheetByName('Form Responses 1')
const values = sheet.getRange(1, 1, sheet.getLastRow(), 1)
.getValues()
.flat()
// Transform the values into a regex expression (pattern)
const pattern = `^(${values.map(_escapeRegex).join('|')})$`
// Contruct and set validation
const validation = FormApp.createTextValidation()
.setHelpText("Email already exist")
.requireTextDoesNotMatchPattern(pattern)
.build()
item.setValidation(validation)
}
function _escapeRegex(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
Note that this allows users to add non-emails to the field, but not to repeat values.
References
Is there a RegExp.escape function in JavaScript? - Answer by bobince (Stack Overflow)
Class TextValidationBuilder (Google Apps Script reference)
Regular expression (Wikipedia)
I seek an approach by which I can provide user a bespoke Google Sheet dashboard on the basis of some ID that is entered or transferred via URL.
To explain: as of now, raw data sits in a master Google Sheet and is processed and summarised in another Google Sheet dashboard that requires to enter an ID which acts as filter to the raw data so that the summary only presents insights associated with that particular ID and user - that works.
However, Each user should enter only their ID and see their summary. Right now all users have access to the same public Sheet and the possibility of parallel access is problematic.
How may I generate individual Sheets (one per user) that is based on a template?
Is this possible with default functionality, or Apps Script? Any advice is highly appreciated, thank you!
This is one option you can try, you can get the email ID of the user who opens the google spreadsheet like so:
function onOpen(e) {
var email = Session.getEffectiveUser().getEmail()
var ui = SpreadsheetApp.getUi()
ui.alert(email)
//doSomethingSpecificBasedOnEmail(email) call function that fliters data based on email ID
}
Note: There are few nuances to using Session.getEffectiveUser(). Based on permission and security setting, it can give you a blank user/email.
https://developers.google.com/apps-script/reference/base/session#getActiveUser()
Second Option:
If email ID is not an option and since you are ok with users entering an ID to access the data. This code will ask for an ID and create a copy of sheet called template and also set the value of A1 as the ID. The sheet can then use the ID to get ID specific data and make plots.
function onOpen(){
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Get ID:');
// Process the user's response.
if (response.getSelectedButton() == ui.Button.OK) {
var id = response.getResponseText();
var ss = SpreadsheetApp.getActive()
var lookupSheet = ss.getSheetByName(id)
if(lookupSheet == null){
var template = ss.getSheetByName("Template")
var newSheet = template.copyTo(ss)
newSheet.setName(id)
newSheet.getRange(1,1).setValue(id)
newSheet.activate()
} else
{
lookupSheet.activate
}
} else {
Logger.log('The user clicked the close button in the dialog\'s title bar.');
}
}
An example of this can be found here: https://docs.google.com/spreadsheets/d/1RPHUGKi7u9jJVc-3xCaYlrZ8kaHWvpl6gPZxUL1g32Y/edit?usp=sharing
Note: People can see each others sheet though, which I assume based on your post is not an issue. However, if that is not the case the best option is to use google Web App script.
My company has created a Google Form set up to make one of our processes a lot easier. The Google Form is based off of the Master Spreadsheet that contains all of the data inputted from the Form. This spreadsheet then filters out the the form submission and sends the data to each department’s spreadsheet, which as previously stated before, gets all of the information from the "Master Spreadsheet."
We previously had it set up so when employees would go in and approve or deny these requests in their spreadsheet, we would receive an email notification if someone entered "Approved" or "Denied." Recently we changed it so if a certain person submitted a request for a customer, it would be automatically approved, but when we did this the email notification stopped working because no one is manually entering in "Approved" or "Denied" for these requests. It still works when it's manually typed in, but when the cell is automatically filled in, the sendNotification does not work.
Since no actual data is being input into the individual department sheets, we wanted to put the notification trigger on the "Master Sheet," but we are having a heck of a time getting the email notification to send. Basically we want it so if any cell in "Column F" contains a certain list of email addresses it will send an email to a third party notifying them to actually go ahead and make the changes.
Here is what we have so far. Keep in mind this is the code that worked originally. I've tried many different variations of things and have had no luck whatsoever, but I'm not the most educated coder:
function sendNotification() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses 3");
//Get Active cell
var mycell = ss.getActiveSelection();
var cellcol = mycell.getColumn();
var cellrow = mycell.getRow();
var cellValue = mycell.getValue();
var activeUser = Session.getActiveUser();
var recipients = "xxxx#xxxxxxxxxx.com";
var subject = "Update to "+ss.getName();
var body = activeUser + " has marked row " + cellrow + " \"" + cellValue + "\" in \"" + ss.getName() + "\". Visit " + ss.getUrl() + " to view the changes.";
if (cellcol == 2) {
if (cellValue.indexOf('test1#test.com') >= 0) {
var subject = "Lunch Is Served";
Logger.log('Sending approval notification of row ' + cellrow + ' to ' + recipients);
MailApp.sendEmail(recipients, subject, body);
}
}
}
Please keep in mind that we can't use lastRowNumber (at least I didn't think we could) because we already have over one thousand rows listed so the information will fill in to the array automatically.Lastly, our current trigger is set to "On Form Submission" because we want these emails to come in as the forms are submitted.
I have included a sample spreadsheet for you guys to look at. Please use test1#test.com as your email address when completing the form.
The Google Sheet can be found at the following site:
Test Sheet!
Thank you so much and I look forward to reading your responses!
You can't use the line:
var mycell = ss.getActiveSelection();
If that function is running from an "On Form Submit" trigger, there is no active selection. Although, there is a property available to the "On Form Submit" event object that gives the currently edited range. You must get the event object from the form submission. Then you have 3 options. 1) Just get the values 2) Get an object of questions and their values 3) Get the range of the range edited. First, you get the event object that is passed into the function. When the form is submitted, data is automatically made available to the function associated with the On Form Submit trigger. The letter e is typically used as the variable name to get the event object:
function sendNotification(e) {
But you can use any variable name:
function sendNotification(objOfData) {
Apps Script Documentation - Spreadsheet - On Form Submit
function sendNotification(e) {
var cellValue = e.values[4];//Get the value in column 5
I have a google-form that has the following two fields:
Email address: - A text box
Tool: - A radio button
Tool 1
Tool 2
Tool 3
The user would enter his email address and select a tool and click submit. I would like the following message to appear:
Thanks for responding. An email has been sent to you to at entered email address to download selected tool.
I have the following piece of code in the script editor
function emailFormSubmission() {
var form = FormApp.getActiveForm();//the current form
var dest_id = form.getDestinationId(); //the destination spreadsheet where form responses are stored
var ss = SpreadsheetApp.openById(dest_id);//open that spreadsheet
var theFormSheet = ss.getSheets()[0]; //read the first sheet in that spreadsheet
var row = theFormSheet.getLastRow(); //get the last row
var emailid = theFormSheet.getRange(row,2,1,1).getValue();//get column 2 corresponding to the email id. column 1 is timestamp. so, skip that.
var tool = theFormSheet.getRange(row,3,1,1).getValue();//get column 3 corresponding to the selected tool.
form.setConfirmationMessage('Thanks for responding. An email has been sent to you '+ emailid + ' to download' + tool);
}
I have also set the triggers to be Run -> emailFormSubmission, Events -> from Form , onFormSubmit.
What happens is: Suppose the first user ('A') enters his information and clicks submit. His entered information gets displayed correctly. When second user ('B') enters his information and clicks submit, A's information is displayed. When third user ('C') enters his information and clicks submit, then B's information is displayed. I found that the issue is with "getlastrow()" since the spreadsheet is updated after emailFormSubmission is processed.
Whats wrong with the above code? How do I fix this?
UPDATE
Based on #wchiquito's comments, I changed the code to following to make it work.
function emailFormSubmission(e) {
var form = FormApp.getActiveForm();
//Check this link on how to access form response:
//https://developers.google.com/apps-script/understanding_events?hl=en
var responses = e.response;//e is of type formresponse.
var emailid = responses.getItemResponses()[0].getResponse();
var tool = responses.getItemResponses()[1].getResponse();
Logger.log(emailid);
Logger.log(tool);
form.setConfirmationMessage('Thanks for responding. An email has been sent to '+ emailid + ' with instructions to download ' + tool +'. If you do not find our email in your inbox, please check your spam folder');
Logger.log(form.getConfirmationMessage());
}
Remember that the event On form submit (Understanding Events) receives a parameter that has the following structure:
values
range
namedValues
and you can do something like:
function emailFormSubmission(e) {
...
var row = e.range.getRow();
...
}
Try the following code to observe the structure of the parameter e:
function emailFormSubmission(e) {
...
Logger.log(e);
...
}
UPDATE
First, excuse my confusion, I showed you the structure of a Spreadsheet form submit event when you really are using a Form submit event.
Sure enough, a Form submit event has the following structure:
response
Returning an object of type FormResponse.
Therefore, defining the event: On submit form (Form submit event), you can do something like the following:
function emailFormSubmission(e) {
var itemResponses = e.response.getItemResponses();
for (var i = 0, len = itemResponses.length; i < len; ++i) {
Logger.log('Response #%s to the question "%s" was "%s"',
(i + 1).toString(),
itemResponses[i].getItem().getTitle(),
itemResponses[i].getResponse());
}
}
However, the confirmation message set according to the data sent as responses of the form, does not seem very clear, you can set the message, but will not display for the active response, if not for the next.
My first guess is these two lines right here:
var emailid = theFormSheet.getRange(row,2,1,1).getValue();//get column 2 corresponding to the email id. column 1 is timestamp. so, skip that.
var tool = theFormSheet.getRange(row,3,1,1).getValue();//get column 3 corresponding to the selected tool.
When you call getLastRow() on a sheet - you're getting the last row. Sure, but considering the order of events and how these values are processed, you need a +1, to get the most recent submission. Currently you're one row behind when your code runs to update the Form confirmation message.
So just change your code to the following:
var emailid = theFormSheet.getRange(row+1,2,1,1).getValue();
var tool = theFormSheet.getRange(row+1,3,1,1).getValue();
Spreadsheets are the most confusing of Google services, in my opinion. When you get values in the Spreadsheet, they're returned as an [] or [][] depending on what your Range is when you call getValues(). But getRange() on a sheet starts at index 1 (to make it easier to read in code I suppose). Often times I find that I have an off-by-one error because of the way data is passed around. Just keep that in mind as you work with Spreadsheets :)
Short answer: want you want can't be done with Google forms.
Explanation:
form.setConfirmationMessage() sets the confirmation message for the form as stored on the server, not for the current active form. Same applies for example for form.setTitle(). The active form will not be modified. One would expect different behaviour for the confirmation message, but alas, this is not the case.
Yes, you can do this with the add-on "Formfacade".
It's free to use in 1 form.