How to change a form without corrupting concurrent usage?

36 views
Skip to first unread message

David Rudel

unread,
Dec 4, 2019, 8:26:08 PM12/4/19
to Google Apps Script Community
I have a form that aims to get information on users' pizza preferences. It has 3 questions
  • A text question asking for the user's zipcode or country
  • A GridItem question that asks the user's opinions on a list of randomly generated pizzas.
  • A CheckBoxGridItem that asks the user to design his own perfect pizza.
A google-apps script changes the content of the second question every N submissions to allow a larger variety of sample pizzas to be polled.

The problem is that onSubmit events triggered by the submission frequently are missing data for the second question, the question that is being mutated. For example, my onSubmit function, triggered when the form is submitted begins like this:

function onSubmit(e) {
  var time_stamp = e.response.getTimestamp();
  var responses = e.response.getItemResponses()
  var response_id= e.response.getId()

And the responses variable is frequently missing an item at index 1.

Testing suggests that missing data occurs when the form is loaded very soon after another instance is submitted. To put a finer point on it: consider the following scenario:
  1. User A opens form using a hyperlink
  2. User A submits form using a hyperlink
  3. ~4 seconds after User A submits the form, User B opens the form using a hyperlink.
  4. User B submits his answers to the questions.
In this case the ItemResponse for the second question will be missing for user B. User B sees the same for as User A, for the mutation routine has not completed, and the submission event carries information for questions 1 and 3, but data for Item 2 is missing.

If user B waits longer before opening the form, this behavior is not observed. Also, it seems (from an admittedly small sample set) that it does not matter when user B submits his form, but only when he opens it. 

I'm wondering if there is some way to mutate the form that does not cause this problem. The current way I'm doing it is as so:

function overWriteForm()
{
  var pizza_code_list = createPizzaCodes()
  var form = FormApp.getActiveForm()
  var pizza_survey = form.getItems(FormApp.ItemType.GRID)[0].asGridItem()
  
  var pizza_descriptions = []
  
  for (j = 0; j < pizza_code_list.length; j++)
  {
    pizza_descriptions.push(buildPizzaDescription(pizza_code_list[j]))
  }
  
  pizza_survey.setRows(pizza_descriptions)
}


Is there some other way to do that will not cause the behavior described above?

As an aside, I noticed something bizarre---evidently the event object does not give a faithful representation of the questions the user actually answered. If I mutate the form and then read the values of the items from the event object, I see the new items rather than the ones that the user was responding to when the form was submitted!

Alan Wells

unread,
Dec 5, 2019, 8:21:08 AM12/5/19
to Google Apps Script Community
The only thing that I ever get out of a Form event object is the response ID.

var response_id= e.response.getId()

And then I get the Form, and get the response of a particular ID directly from the Form, never from the event object.  Unfortunately, getting item responses out of the event object for a Google Form seems to be unreliable.

The issue with the question 2 grid items not being updated to the new choices if user B opens the Form before user A submits the Form can't be avoided, I don't think.  I'm assuming that the question 2 grid items are being changed from code that runs when the Form is submitted.  If multiple users have the Form open at the same time, their Google Form can't be dynamically updated as the Form is open.  That situation isn't a "race" condition because multiple instances of the code aren't running at the same just because the Form is open.

If multiple users submit the Form about at the same time, then you could get a situation where subsequent instances of the code are running before the previous one completes.  That can cause variable values in the first instance to be overwritten, causing the first instance of the running code to be using values from the second instance of the code. To deal with that situation, you should use LockService.  Although, I don't 100% trust LockService either, depending on how heavy the use of the Form is.  But, if it works for you, then I'd use it.

You could use a Web App instead of a Google Form.  With a Web App, you can change the questions when the form is open.  You could also put the Web App into a Google Site.



Clark Lind

unread,
Dec 5, 2019, 10:28:41 AM12/5/19
to Google Apps Script Community
If you want a dynamic front-end form, you may have to just serve the html with your embedded javascript rather than trying to make a Google form do what you want. That way, the front-end can change for each user as they need without touching your back-end until they hit submit. Google forms are an 80% solution for most simple scenarios, but you might have to put in a lot of hard work to make them (& Apps script) do what you want when there might be an easier way with an html form/javascript. Just a thought for you to consider; I wouldn't know how to code it. There are Youtube videos by a few folks that might be of help. (Ref 1, Ref 2, Ref 3).

David Rudel

unread,
Dec 5, 2019, 10:49:51 AM12/5/19
to Google Apps Script Community
Thanks for the suggestion to get data from the form rather than from the event. I'll look into that.

It doesn't really bother me that User A and User B see the same form. For my purposes, that is fine. I was just trying to see if there was a way to avoid losing User B's response data. I'll take a look at what I can get using the response_id rather than relying on the event object.
Reply all
Reply to author
Forward
0 new messages