Apps Script - Get existing ListItem on FormApp - google-apps-script

I'm trying to populate a ListItem inside a Form whith data from a SpreadSheet. Each row would be a choice.
So I have a ListItem question in my form and what I couldn't find out is: How can I acess an existing instance of a ListItem question in a form?
I have a : var form = FormApp.getActiveForm();, but how can I do something like "getFormAppListItem()"
And another doubt I have is... If I create a ListItem inside my function (addListItem() method), will it be recreated everytime someone opens the form (is a public survey)?

var field1 = SpreadsheetApp.openById("XXXXXXXXXXXXXXXXXXXX").getSheetByName("Sheet1").getRange(2,1).getValue;
var field2 = SpreadsheetApp.openById("XXXXXXXXXXXXXXXXXXXX").getSheetByName("Sheet1").getRange(3,1).getValue;
var field3 = SpreadsheetApp.openById("XXXXXXXXXXXXXXXXXXXX").getSheetByName("Sheet1").getRange(4,1).getValue;
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
var item = form.addMultipleChoiceItem();
item.setTitle('Choose the Pet you prefer').setChoices([
item.createChoice(field1),
item.createChoice(field2)
item.createChoice(field3)
])
.showOtherOption(true);
Please see the details here https://developers.google.com/apps-script/reference/forms/multiple-choice-item. Hope this helps.

Related

Using Google apps script apply "go to sections based on answer" on Google Form ERROR Message : list.createChoice is not a function

I am using FORM RANGER to auto-populate data, but once it populate,Multiple choice go to sections based on answer always erase.
I am trying use GAS to keep branching while this FORM open, but ERROR message "list.createChoice is not a function".
I've read similar question before and working with this problem about 2 days but still can't figure it out......
Following is my code, wish someone can help me, thank you!
function GoToPage() {
var form = FormApp.openById('');
var list = form.getItems(FormApp.ItemType.MULTIPLE_CHOICE);
var list1 = form.getItems(FormApp.ItemType.MULTIPLE_CHOICE)[0].asMultipleChoiceItem().getChoices().map(choice => choice.getValue());
var choice1 = list1[0];
var choice2 = list1[1];
var choice3 = list1[2];
var pagelist = form.getItems(FormApp.ItemType.PAGE_BREAK);
var pagebreak01 = pagelist[2].asPageBreakItem();
var pagebreak02 = pagelist[3].asPageBreakItem();
var pagebreak03 = pagelist[4].asPageBreakItem();
var choices = [];
choices.push(list1.createChoice(choice1,pagebreak01));
choices.push(list1.createChoice(choice2,pagebreak02));
choices.push(list1.createChoice(choice3,pagebreak03));
list.setChoices(choices);
}
Addition:
I have four multiple choices, auto-populated by FORM RANGER from spreadsheet,and set four choices go to four sections one by one.
Once I execute, it shows:
「TypeError: list1.createChoice is not a function
GoToPage
# GOTOSEC.gs:16」
I thought this error might because input variables can't fit with "createChoice" function, but I read a lot of previous post and tried many times with other syntax,still can't work :(
Finally, I solved it with Rubén's solution, and substitute this kind of syntax:
choices.push(list1.createChoice(choice,pagebreak));
To this:
choices.push(list.asMultipleChoiceItem().createChoice(list1[i], pagebreak));
The problem is that the third line,
var list = form.getItems(FormApp.ItemType.MULTIPLE_CHOICE);
returns a Array. Assuming that you want to modify the first multiple choice question, replace this line by
var list = form.getItems(FormApp.ItemType.MULTIPLE_CHOICE)[0];

How can I add choices in a Google Form with Google Apps Script

I'm trying to master creating Google Forms programmatically, but can't assign choices to a multiple-choice item. I can create the item (testQuestion) and give it a title, but my createChoice() statements don't add choices.
Here's my code, based on https://developers.google.com/apps-script/reference/forms/page-navigation-type
function testCreateChoices() {
/* modification of
testPageNavigation()
to see how to import choices from a range on sheet
*/
// Create a form
var form = FormApp.create('createChoice Test');
// add a multiple-choice item
var testQuestion = form.addMultipleChoiceItem();
testQuestion.setTitle('Anything here?');
var whatsis = testQuestion.createChoice('bozzle');
var firstChoice = testQuestion.createChoice('this');
testQuestion.createChoice("that");
testQuestion.createChoice("the other");
testQuestion.createChoice("Ouch!");
//add a new multiple-choice item and a pagebreak item
var item = form.addMultipleChoiceItem();
var pageBreak = form.addPageBreakItem();
// Set some choices with go-to-page logic.
var rightChoice = item.createChoice('Vanilla', FormApp.PageNavigationType.SUBMIT);
var wrongChoice = item.createChoice('Chocolate', FormApp.PageNavigationType.RESTART);
// For GO_TO_PAGE, just pass in the page break item. For CONTINUE (normally the default), pass in
// CONTINUE explicitly because page navigation cannot be mixed with non-navigation choices.
var iffyChoice = item.createChoice('Peanut', pageBreak);
var otherChoice = item.createChoice('Strawberry', FormApp.PageNavigatio[enter image description here][1]nType.CONTINUE);
item.setChoices([rightChoice, wrongChoice, iffyChoice, otherChoice]);
}
Here's what I get, with the choices "bozzle" and so on not displayed, and an image of what I want but can't create.
Many thanks for any help!
Here's a screenshot, with no labels/choices under "Anything here?"
And a mockup with "bozzle", "this" and so on as choices
The reason you are not seeing the options for the testQuestion is because you didn't set the choices for the question.
Therefore, I suggest you update the bit where you create your first question to this:
var testQuestion = form.addMultipleChoiceItem();
testQuestion.setChoices([testQuestion.createChoice('bozzle'), testQuestion.createChoice('this'), testQuestion.createChoice("that"), testQuestion.createChoice("the other"), testQuestion.createChoice("Ouch!")]);
The createChoice method is used to create the choice items only and in order to actually add them to the question, you have to use the setChoices method as well.
Reference
Apps Script Class MultipleChoiceItem - createChoice(value);
Apps Script Class MultipleChoiceItem - setChoices(Choice).

How to make a simple authentication in Google Forms using Google apps script?

Objective & Implementation
I created a questionnair using Google Forms. I want to authenticate users using a simple one time password that should be entered in the first question.
The password is stored inside a spreadsheet that contains only one cell. https://prnt.sc/r8i8q1
The script below reads the content of this cell and create a custom validator against the value of the first item of the form.
function validatePassword() {
var passwordSpreadsheet = "[passwords_spreadsheet_id]";
var ss = SpreadsheetApp.openById(passwordSpreadsheet);
var passwordSheet = ss.getSheetByName("passwords");
var form = FormApp.getActiveForm();
var items = form.getItems();
var item = items[0];
if (item.getType() == 'TEXT') {
var textItem = item.asTextItem();
var namedRanges = passwordSheet.getNamedRanges();
if (namedRanges.length > 0) {
var range = namedRanges[0].getRange();
var values = range.getValues();
var currentPassword = values[0][0];
var textValidation = FormApp.createTextValidation()
.requireTextMatchesPattern(currentPassword)
.build();
textItem.setValidation(textValidation);
}
}
}
Current Situation
The above code is working as expected for one password, but, the problem is that I couldn't find a way to create a custom validator against range of values.
Questions
Is there any way to have this simple authentication mechanisim in Google Forms via Google Apps Script?
Is there a way to make this password a One Time Only password?
If (1.) and (2.) are not available, then, what is the best way to authenticate Google Forms?
Thank you in advance!
Solution
Using Apps Script
The following piece of code will make a password verification according to what you right on the Spreadsheet as a password. It has comments to explain what line of code does:
function validatePassword() {
// Create new custom form
var form = FormApp.create('New Form');
var ss = SpreadsheetApp.openById('SHEETID');
var password = ss.getSheetByName('SHEETNAME').getRange('A1').getValue();
// Create first question to check the password, it must be required so that the user does not have access to the rest
// of the form if failed to log in
var item = form.addTextItem().setRequired(true);
item.setTitle('TEST TITLE');
// Create validation for this question matching the password that we got from the sheet
var textValidation = FormApp.createTextValidation()
.setHelpText('You must enter the right password')
.requireTextMatchesPattern(password)
.build();
item.setValidation(textValidation);
}
Using the UI
The esieast way to validate forms with password is to use the custom functionalities of Google forms. In your case you should follow these steps:
In the first section of your form only place a required short text answer.
Go to the three dots in the lower right part of the question and select Response Validation
Then in the options change them to Regular expression, Matches and introduce your desired regular expression (it could just be a String) and the right error message.
Here is an example of this in action:
I hope this has helped you. Let me know if you specifically need to get the passwords from the Spreadsheet. Let me know if you need anything else or if you did not understood something. :)

Need to move ID to Google Form

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.

handler design for dynamically created listboxes

I'm trying to make a UI that allow users to select an action for each agenda item in a spreadsheet. After a user select an action, I would like to update the spreadsheet with the selection. Since the data in the spreadsheet are not static, the UI was written dynamically.
This is how I created the listboxes :
// add labels and a drop down box of actions for each agenda item mark for today
for (i = 0; i < labels.length; i++) {
// labels is an array of objects
var topic = labels[i]['topic'];
// add label to grid
myGrid.setWidget(i, 0, myApp.createLabel(topic));
// the id of each listbox is the content of its corresponding label
var id = ObjApp.camelString(topic)
var lboxActions = myApp.createListBox().setId(id);
//add items to listbox
lboxActions.addItem('Select');
lboxActions.addItem('Add to agenda');
lboxActions.addItem('Move to another meeting');
lboxActions.addItem('Move to a special meetin');
lboxActions.addItem('Move to email');
//add drop down list to grid
myGrid.setWidget(i, 1, lboxActions);
}
I have 3 questions:
1) Which is a better design?
a) Design 1: a save button next to each listbox.
b) Design 2: one submit button at the bottom to save every entry
2) How would I collect information on what the user select? How would I write such handlers? I added the following code for each design but I don't think I'm doing it right.
a) Design 1: the following lines of code were added to the for loop described above
var buttonSave = myApp.createButton('Save');
myGrid.setWidget(i, 2, buttonSave);
var handlerSelection = myApp.createServerHandler('selectAction');
handlerSelection.addCallbackElement(mainPanel);
buttonSave.addClickHandler(handlerSelection);
b) Design 2: the following lines of code were added outside the for loop
//update spreadsheet when user click "submit"
var handlerUpdate = myApp.createServerHandler('responseToSubmit');
handlerUpdate.addCallbackElement(mainPanel);
buttonSubmit.addClickHandler(handlerUpdate);
mainPanel.add(myGrid);
mainPanel.add(buttonSubmit);
myApp.add(mainPanel);
3) How do I write functions for the handlers? These are not correct because I wasn't able to extract the information from the list boxes.
a) Design 1
function responseToSave(e) {
var name = e.parameter.source;
var selection = e.parameter.name;
var selectionObj = new Object();
selectionObj['status'] = selection;
selectionObj['name'] = name;
choicesMade.push(selectionObj)
Logger.log(choicesMade);
return choicesMade;
}
b) Design 2
function responseToSubmit(e) {
var myApp = UiApp.getActiveApplication();
for (i=0; i < labels.length; i++) {
var lboxId = ObjApp.camelString(labels[i]['topic']);
//[EDIT] e.parameter.lboxId would not work because lboxId is a string
var selection = e.parameter[lboxId];
choicesMade[labels[i]] = selection;
}
Logger.log(choicesMade);
return choicesMade;
}
Thanks
Q1:
The design purely depends on what your application is intended to do and how your users use it. There is no 'better' design - each of them has its own pros and cons and the choice would be based on how your app is used.
However, do also consider Design 3 which is saving the changes when the dropdown box is changed. It will be one click less for the user
Q2 and Q3:
You should use the setName on the listBox
var lboxActions = myApp.createListBox().setId(id).setName(id);
I generally use the same string for the id and the name to avoid confusion, but you should use setName
After that you can access the item selected in the handler function as
e.parameter.id
Finally, on buttonSave, you should use the addClickHandler instead of addChangeHandler.