I am creating a submission document through Google Forms & Google Spreadsheets. I have created a form that emails data for approval. The email includes a URL link which is contains a unique ID. This link is connected to a second form for approval/denial of the submission. I am having difficulty getting this unique ID linked to the approval/denial process form. I believe I need to reference this ID so that it will approve the correct entry in my spreadsheet. Can someone point me in the right direction on how to reference my ID through my second form or give me another idea on how to do this?
var d = new Date();
var ID = d.getTime();
approvalLink = "docs.google.com/forms";
approvalLink = approvalLink + "?id=" + ID
Unfortunately, there is no way to do this on the live forms. Form Script code doesn't run until after the form is submitted.
However you could generate a pre-filled form url for the 2nd approval/denial form that fills in a question with your ID (PS. Think about using a UUID instead of timestamp).
var form = FormApp.openById("2nd Form ID");
var response = form.createResponse();
var items = form.getItems();
var item = items[0].asTextItem();
var itemResponse = text.createResponse('my text');
response.withItemResponse(itemResponse);
var url = response.toPrefilledUrl();
You use this url to present a form with that questions that already has your ID filled in. Then when your 2nd form is submitted you can reference that question.
The url this generates will end in something like: ?entry.2623445234=SomeText.
Related
I'm looking for a way to 'pre fill' a google form with specific data from a google spreadsheet. The form will have the same 'standard' questions for everyone, but the data in the first two question will be 'prefilled' with unique data from an existing google spreadsheet. The data will be unique based on their email address in the existing spreadsheet.
SOURCE SPREADSHEET EXAMPLE
Col 1 Col 2 Col 3
email name birthday
#mike Mike Jones May 9th 1975
#jim Jim Smith April 19th 1985
FORM EXAMPLE ONE
Question 1 - prefilled with data (Mike Jones) from a google spreadsheet.
Question 2 - prefilled with data (May 9th 1975) from a google spreadsheet.
Question 3 - blank (awaiting user response)
Question 4 - blank (awaiting user response)
FORM EXAMPLE TWO
Question 1 - prefilled with data (Jim Smith) from a google spreadsheet.
Question 2 - prefilled with data (April 19th 1985) from a google spreadsheet.
Question 3 - blank (awaiting user response)
Question 4 - blank (awaiting user response)
Does anyone know if this can be done? If yes, any help or direction will be GREATLY appreciated.
Thank you in advance!
Todd
You can create a pre-filled form URL from within the Form Editor, as described in the documentation for Drive Forms. You'll end up with a URL like this, for example:
https://docs.google.com/forms/d/--form-id--/viewform?entry.726721210=Mike+Jones&entry.787184751=1975-05-09&entry.1381372492&entry.960923899
buildUrls()
In this example, question 1, "Name", has an ID of 726721210, while question 2, "Birthday" is 787184751. Questions 3 and 4 are blank.
You could generate the pre-filled URL by adapting the one provided through the UI to be a template, like this:
function buildUrls() {
var template = "https://docs.google.com/forms/d/--form-id--/viewform?entry.726721210=##Name##&entry.787184751=##Birthday##&entry.1381372492&entry.960923899";
var ss = SpreadsheetApp.getActive().getSheetByName("Sheet1"); // Email, Name, Birthday
var data = ss.getDataRange().getValues();
// Skip headers, then build URLs for each row in Sheet1.
for (var i = 1; i < data.length; i++ ) {
var url = template.replace('##Name##',escape(data[i][1]))
.replace('##Birthday##',data[i][2].yyyymmdd()); // see yyyymmdd below
Logger.log(url); // You could do something more useful here.
}
};
This is effective enough - you could email the pre-filled URL to each person, and they'd have some questions already filled in.
betterBuildUrls()
Instead of creating our template using brute force, we can piece it together programmatically. This will have the advantage that we can re-use the code without needing to remember to change the template.
Each question in a form is an item. For this example, let's assume the form has only 4 questions, as you've described them. Item [0] is "Name", [1] is "Birthday", and so on.
We can create a form response, which we won't submit - instead, we'll partially complete the form, only to get the pre-filled form URL. Since the Forms API understands the data types of each item, we can avoid manipulating the string format of dates and other types, which simplifies our code somewhat.
(EDIT: There's a more general version of this in How to prefill Google form checkboxes?)
/**
* Use Form API to generate pre-filled form URLs
*/
function betterBuildUrls() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Sheet1");
var data = ss.getDataRange().getValues(); // Data for pre-fill
var formUrl = ss.getFormUrl(); // Use form attached to sheet
var form = FormApp.openByUrl(formUrl);
var items = form.getItems();
// Skip headers, then build URLs for each row in Sheet1.
for (var i = 1; i < data.length; i++ ) {
// Create a form response object, and prefill it
var formResponse = form.createResponse();
// Prefill Name
var formItem = items[0].asTextItem();
var response = formItem.createResponse(data[i][1]);
formResponse.withItemResponse(response);
// Prefill Birthday
formItem = items[1].asDateItem();
response = formItem.createResponse(data[i][2]);
formResponse.withItemResponse(response);
// Get prefilled form URL
var url = formResponse.toPrefilledUrl();
Logger.log(url); // You could do something more useful here.
}
};
yymmdd Function
Any date item in the pre-filled form URL is expected to be in this format: yyyy-mm-dd. This helper function extends the Date object with a new method to handle the conversion.
When reading dates from a spreadsheet, you'll end up with a javascript Date object, as long as the format of the data is recognizable as a date. (Your example is not recognizable, so instead of May 9th 1975 you could use 5/9/1975.)
// From http://blog.justin.kelly.org.au/simple-javascript-function-to-format-the-date-as-yyyy-mm-dd/
Date.prototype.yyyymmdd = function() {
var yyyy = this.getFullYear().toString();
var mm = (this.getMonth()+1).toString(); // getMonth() is zero-based
var dd = this.getDate().toString();
return yyyy + '-' + (mm[1]?mm:"0"+mm[0]) + '-' + (dd[1]?dd:"0"+dd[0]);
};
I'm trying to pre fill the date in google form. so It will put the date of the day it filled as default.
I tried using the TODAY() function in google sheets . so i change the url to get the date from cell in google sheets . works for everything except the Date..
https://docs.google.com/forms/d/e/1FAIpQLSf7cdT34eHp-GXagq3DsnxX1MD_c-G6lbF6yFWOMnUvtPYUUQ/viewform?entry.178275308=**&A6&**
Any idea how can i do it in the simplest way?
Deploy your script as a Web App
Publish your Apps Script as a Web App and provide the URL of the web deployment to the users
Write your code inside a doGet() function, so it gets evaluated every time a user open the link
Get the current date with new Date() and pass it as an itemResponse to a prefilled Form
Create a redirection to the URL to the prefilled form with the Java Script method window.top.location.href inside of <script> </script> tags and return it with HtmlService
// will be automatically run every time the user opens the URL of the web deployment
function doGet(){
//open your form
var form = FormApp.openById('1Zs5Wo0wS9esNkcq8ztOZmQs3f5NrO7hgJ_0fYk262z4');
//get the questions
var questions = form.getItems();
//get the question where you want to prefill the date as an answer, e.g. first question
var question1=questions[0];
//get the current date
var time=Utilities.formatDate(new Date(), "GMT+2", "dd-MM-yyyy");
// prefill form with current date
var prefilledTime=form.createResponse().withItemResponse(question1.asTextItem().createResponse(time));
// Get the link to the prefilled form
var URL=prefilledTime.toPrefilledUrl();
// redirect to the prefilled form URL dynamically created above
return HtmlService.createHtmlOutput("<script>window.top.location.href=\"" + URL + "\";</script>");
}
If you just want the date the Form is submitted, Google Forms provides this automatically in it's Timestamp.
If you want to pre-fill a date from an existing spreadsheet, then provided you obey Google's date-format, you can use the URL approach (months & days must be 2 digits i.e. "01" not "1").
=substitute('Sheet_with_Form_Link'!$A$1,"2099-01-01",text(Sheet_with_date!A1,"yyyy-mm-dd"))
WhereSheet_with_Form_Link'!$A$1 is a cell in a Sheet in a Google SpreadSheet containing the URL obtained via 'Get Prefilled Link'
"2099-01-01" is the data you Pre-filled into the Form whilst using 'Get Pre-filled Link'
Sheet_with_date!A1 is a cell in a Sheet in a Google SpreadSheet containing your desired date e.g. one of
=today()
1920/03/26
17Oct2002
I took the code from ziganotschka as base, but I had to make some changes, maybe it helps somebody:
function doGet(){
//open your form open by URL
var form = FormApp.openByUrl('https://docs.google.com/forms/d/1M-zgHyDOz2ob5StkwIoDCShJ9tePw-I5TGhdx/prefill')
//get the questions
var questions = form.getItems();
//get the question where you want to prefill the date as an answer, e.g. first question
var question1=questions[0];
//get the current date
var time=new Date();
// prefill form with current date
var prefilledTime=form.createResponse().withItemResponse(question1.asDateItem().createResponse(time));
// Get the link to the prefilled form
var URL=prefilledTime.toPrefilledUrl();
// redirect to the prefilled form URL dynamically created above
return HtmlService.createHtmlOutput("<script>window.top.location.href=\"" + URL + "\";</script>");
}
And when you're done, don't forget to Publish -> Deploy as a Web App...
I have multiple Google Forms with identical response fields inputting into a certain Google Sheets, and there is no way of telling them apart other than their names and descriptions. Using Google Apps Script, is there any way I can add the name and/or description of the Google Form into the Sheets, along with everything that is normally added to the Sheets? I did a bit of research about something with "source" but I have no idea how to implement it.
Thanks!
You can accomplish this by going to your form in edit mode selecting "Script Editor" and pasting the below code into the script. You will need to click on the "Trigger" button (looks like a clock, if you can't find it follow here https://developers.google.com/apps-script/guides/triggers/installable). Click Add Trigger and select event type "On Form Submit"
function writeFormTitle(){
//Get Form
var form = FormApp.getActiveForm();
//Get Form's Title
var formTitle = form.getTitle();
//Get the Write To Spreadsheet ID where the data will be written to
var destinationSpreadsheet = form.getDestinationId();
//Activate that Spreadsheet by the destinationSpreadsheet ID
var sheet = SpreadsheetApp.openById(destinationSpreadsheet).getActiveSheet();
//Find the last column and row
var writeToColumn = sheet.getLastColumn()+1;
var writeToRow = sheet.getLastRow();
//Write title to Spreadsheet next to submitted data.
sheet.getRange(writeToRow, writeToColumn, 1, 1).setValue(formTitle);
}
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.
I'm looking for a programmatic way to automate the generation of pre-filled URLs for google forms.
In a recent update, Google introduced a new Forms product to Google Docs. If you open the tools menu in a spreadsheet, you'll see some new options.
In the new Form Responses menu, one option is "Get pre-filled URL". This opens up a dialog containing a version of your form that you can fill out, and when you submit it, you receive a URL that can be used to open a Live Form with the data you pre-filled ready and waiting for you. The URL looks something like this...
https://docs.google.com/forms/d/--Form-ID--/viewform?entry.1094330118=Something&entry.1471717973=stack#example.com&entry.540962741&entry.787941281&entry.1873343651
The questions from the form have a fixed identity, e.g. entry.1094330118. They may be pre-filled with a value (entry.1094330118=Something) or blank (entry.7879412).
In apps-script, I'd like to generate these pre-filled URLs for users of my form, so I can provide them for updates. My users are not members of an Apps Domain, so I don't have the option of embedding an Edit your response link.
If I can get the information about the form, I will be able to piece together the URL. While I can go through the UI to create one URL, and dissect it to get the info for that form, I want a solution that will work with arbitrary forms.
How can I programmatically determine the question IDs?
With the new
Forms product, is the form available to me through any apps-script
APIs? (I know about getFormURL() - that's not what I mean.)
Armed with a question ID, can I get more information about the question? (Question text, type, etc.)
I required something similar for users to go and edit their response, take a look here: http://productforums.google.com/forum/#!topic/docs/LSKKCR3VHC8
Copy / paste code below:
function assignEditUrls() {
var form = FormApp.openById('1MonO-uooYhARHsr0xxxxxxxxxxxxxxxxxxxxx');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses');
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = 4; // column number where URL's should be populated; A = 1, B = 2 etc
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}
This is not possible right now but this request is being tracked on the Issue Tracker here. Please add your use cases there and watch it for updates.
I found no way to create a pre-filled URL from the form id itself. It is possible if the form has already an answer:
var form = FormApp.openById('1nGvvEzQHN1n-----_your_for_id_----zemoiYQA');
var responses = form.getResponses();
Logger.log(responses[0].toPrefilledUrl());
referring to this answer, it can be used to create prefilled urls, by replacing the last line like this:
instead of
FormResponse.submit();
it will be
FormResponse.toPrefilledUrl();