Dynamically fill form fields based on other responses before submit - google-apps-script

I have a form I want to dynamically change, I have read through the documents but I cannot seem to find any definitive answer. Can I make my form remove choices from dropdown lists because they used radio button #2 for the 3rd question? Can I format text from question 1 and use it to pre-fill question 6 with the same answer (by default, needs to be changeable)?
Basically I need to use code to determine if the address was spelled with shortforms (st, rd, cres, ct) and lengthen and capitolize them (Street, Road). I don't even know if this is possible. If it is can anyone provide sample code or point me to the right help docs, it would be appreciated. If not is this doable on a webserver if some of my multiple choice options need to be read from a google spreadsheet? Could i do it through google Sites?

Have you looked at the Form Class of Google Apps Services?
Class Forms
It states:
Forms can be accessed or created from FormApp.
For example, you can use:
addTextItem()
OR:
createChoice(value)
Google Documentation
// Open a form by ID and add a new multiple choice item.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
var item = form.addMultipleChoiceItem();
item.setTitle('Do you prefer cats or dogs?')
.setChoices([
item.createChoice('Cats'),
item.createChoice('Dogs')
])
.showOtherOption(true);
You don't want to open a new form, but use the currently open one.
/**
* Adds a custom menu to the active form, containing a single menu item for
* invoking checkResponses() specified below.
*/
function onOpen() {
FormApp.getUi()
.createMenu('My Menu')
.addItem('Check responses', 'checkResponses')
.addToUi();
}
Check current responses?
/**
* Gets the list of responses and checks the average rating from the form
* created in createForm() above.
*/
function checkResponses() {
var form = FormApp.getActiveForm();
var responses = form.getResponses();
var score = 0;
for (var i = 0; i < responses.length; i++) {
var itemResponses = responses[i].getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
if (itemResponse.getItem().getType() == FormApp.ItemType.SCALE) {
score += itemResponse.getResponse();
}
}
var average = score / responses.length;
FormApp.getUi().alert('The score is ' + average);
}
}

You could use Apps Script HTML Service; write HTML to create a custom form; write the JavaScript code to do what you want; then add the Apps Script to the Google Site. Or just run the Apps Script HTML Service as a website on it's own. But this option requires you to be able to write HTML and JavaScript. What you want to do is possible.
As far as creating the custom form, checking the user input and changing it, that can be done in Apps Script HTML Service. Then you need to save the data somewhere. Google Forms is made to be user friendly to people who don't have programming knowledge.
It seems like you are just looking for general information on what is possible and not possible with different products so that you can make a choice.
For reading about HTML Service, click the following link as a place to start:
Google Documentation HTML Service

Related

Keep images when adding choices to Google Forms with Apps script

I'm using google scripts to add new choices to a checkbox item in a form every time the form gets submitted. Some of the existing checkbox-items have images attached that users see when filling in the form.
My problem is that every time my script gets run, it removes the images from the checkbox-items. Is there a way to keep the images attached to the form, while adding new choices to it?
(part of) my code:
// retrieve form-checkbox object
var item = form.getItems(FormApp.ItemType.CHECKBOX)
.filter(function(item){
return item.getTitle() === 'Top 5 films';
})[0].asCheckboxItem();
//make 2 lists, 'choices' with all choices in the checkbox obj
// 'existingChoicesTitles' with all the titles of the choices.
var choices = item.getChoices();
var existingChoicesTitles = choices.map(function(value){
return value.getValue();
})
//check if obj in list 'values' already exists in array 'choices, if not add to
//'choices'
for (i = 0; i < values.length; i++) {
if (existingChoicesTitles.includes(values[i]) == false){
choices.push(item.createChoice(values[i]));
}
}
//set 'choices' list as new list of choices
item.setChoices(choices);
Unfortunately there is currently no way to do that.
There is an active Feature Request for the ability to add these kind of images with the Apps Script FormApp.
Add Images to Form Items
I would suggest that you go and mark the ☆ on the issue to let Google know that you would like this functionality, and also to subscribe to updates. You might also want to add in your experience and use case in a comment.
In your case it seems that to add an item to the checkbox list, Apps Script regenerates all the checkbox items, and since FormApp doesn't support these types of images, it doesn't include them when they are regenerated.
For your use case there doesn't seem to be a practical workaround apart from simply not using images in this way if they are to be modified with Apps Script.
If you are willing to put in some extra work, you might want to implement the form as a simple web app. Then you would have almost infinite flexibility and far more functionality.
Web App example
This is a very simple example of a Web App that shows an input box and a button to send the info to the 'back-end', which in this example is Code.gs
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile("index")
}
function receiveInfo(formResponse) {
Logger.log(formResponse)
}
index.html
<!DOCTYPE html>
<html>
<body>
<input type='text' id='input'></input>
<button id=main>Send Info</button>
<script>
function main(){
const input = document.getElementById('input')
const info = input.value
google.script.run.receiveInfo(info)
}
const mainButton = document.getElementById("main")
mainButton.addEventListener('click', () => main())
</script>
</body>
</html>
References
Feature Request
Web apps
Test a web app deployment
Client-to-server communication

How to find Google Form ID

Update! The Form ID is in the web address.
Someone kindly pointed out to me (outside of Stack Overflow) that the Form ID which identifies the form can be found in the web address. Example:
https://docs.google.com/forms/d/1y9XMjvZi_wlFC2FN64cdafIyGuM_7UOsn1Q61PXv5MQ/edit
Where the bolded text is the Form ID.
Original:
Apologies in advance, as I am not an experienced script writer and may use improper jargon.
But - I found the response to this question when googling about how to find the Form ID element in a Google Form, but the answer is old and my problem is similar. I have tried searching the "Inspect Element" data and still cannot identify the ID attribute. I've tried searching the code for:
data-item-id="##########", or
aria-describedby="i.desc.########## i3"
for="entry_XXXXXXX"
Still no luck. Does anyone have an updated suggestion for finding the Form ID? For reference, I am using the script below as my starting point. This is taken from a different/old form, but is similar in functionality so I was hoping to leverage it. I am trying to find my Form's ID (such as that as in line 6-7).
/**
* #NotOnlyCurrentDoc
* Limit OAuth scope to only current spreadsheet rather than all sheets in drive
*/
function onSubmit(e) {
var form = FormApp.openById('1eccBQ7Bs34Z54keGHeR8HDXmiP1UqxMi9vSDWNv6zgs');
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master');
var data = sheet.getDataRange().getValues();
//var urlCol = 26;
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 = 27, resultUrls.length).setValues(resultUrls);
return resultUrls;
};
As the OP mentioned in the question body, the Form ID could be found in the Google Form URL, but hte OP missed to mention that this URL is the edit URL, not the "view" URL.
The form owner also could find the form ID by using the web-browser developer tools by searching for data-redirect-url which has assigned the Form URL:
data-redirect-url="https://docs.google.com/forms/d/form_id/edit?usp=redirect_edit_m2"
As mentioned by the OP the Form ID is between https://docs.google.com/forms/d/and /edit.
Besides looking at the Form URL, the form ID could be retrieved by using Google Apps Script. The easier way is to use a bounded script similar to this:
function getActiveFormID(){
const id = FormApp.getActiveForm().getId();
console.log(id);
}
Another way is by using the Drive Service. The following example assumes that there is only one file named "My Form":
function getFormId(){
const id = DriveApp.searchFiles(`title contains "My Form"`).next().getId();
console.log(id);
}
From Google Chrome, open the form (view mode, not edit).
Hit F12.
In the Elements window pain,
expand <body>
expand <script type = "text/javascript" nonce> == $0
You should see:
var FB_PUBLIC_LOAD_DATA with each element you created on their form and their respective Element ID.

Highlight a name of current user in Google Sheets using Google Apps Script

I'm working on spreadsheet with table that contains names of workers and their availability during whole year. My goal is to highlight cell with proper name when specific person opens the sheet. All users have their google mail in first_name.last_name#gmail.com schema.
I've already made some code which find name and do bold action on active user's name, you can see it below:
function onOpen(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for(var k = 0; k<sheets.length; k++)
{
var data = sheets[k].getDataRange().getValues();
var user = Session.getActiveUser().getEmail();
var splitname = user.split("#")[0];
var first = splitname.split(".")[0];
var last = splitname.split(".")[1];
var formatted_first = first.charAt(0).toUpperCase() + first.slice(1);
var formatted_last = last.charAt(0).toUpperCase() + last.slice(1);
var name = formatted_first + " " + formatted_last;
for(var i = 0; i<data.length;i++)
{
if(data[i][0] == name)
{
var a = i+1;
}
}
sheets[k].getRange(a,1).setFontWeight("bold");
}
}
The problem is that:
I don't know how to perform an action temporarily, only for time when sheets is open.
After writing code I realized that bold action will be visible for all active users, so if one user opens the sheet when the other has it already open and not close yet, he will see not only his name highlighted but also that other user's name.
Soo, my question is whether there is any possibility to make changes visible only for user that made them and how to perform the highlighting only while sheet is open.
If you know any google feature which makes it possible without using the macro, it would be the best solution. Maybe my research wasn't good enough.
Thank you in advance for help!
Soo, my question is whether there is any possibility to make changes visible only for user that made them and how to perform the highlighting only while sheet is open.
No, there isn't any possibility to do that. The alternatives are to have one spreadsheet for each user or to edit the sharing settings to allow only one user to access the spreadsheet besides the owner but you will have to assume that the owner and the current editor will be able to see the changes made by the other.
NOTE: Filter Views allow users to apply filter settings visible only for the user who is using the filter view but any change made to the filtered data will be viewable by the other users.

Add previous responses to form

I am creating a sign up sheet where people list what they will bring to an event. I would like to modify a Section Header at the start of the form that shows who has signed up to bring what, (pulled from the spreadsheet that collect the data) such that people can see what is already being brought to the event. I am trying to set this on the "On Open" event such that each time the form is loaded people can see other's responses.
I can connect to the spreadsheet via SpreadsheetApp.getActiveSheet() and then get the data. I thought I could add the info from the spreadsheet to the section header when the form is being opened. When I open the form it does not seem to execute this code:
function onFormLoad() {
var s = SpreadsheetApp.getActiveSheet();
var form = FormApp.getActiveForm();
var items = form.getItems();
for (var i = 0; i < items.length; i++){
if (items[i].getType() == FormApp.ItemType.SECTION_HEADER){
items[i].setTitle("Yes");
items[i].setHelpText("This is where I want to put the data...");
}
}
}
If I run this code from the editor it does indeed add the section header. I need it to run when others open the form.
You should add this code in the onFormSubmit event, you can learn more about the various events here https://developers.google.com/apps-script/understanding_events.
If I am not mistaken, you will need to add the trigger explicitly, read more about triggers here : https://developers.google.com/apps-script/understanding_triggers

How to generate a pre-filled form URL for Google 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();