This bug has me completely confused. I am auto-creating a google form (quiz). Periodically (but quite often) the multiple choice items are missing choices, this often happens once the page is refreshed. That is, the answer options look like they are created correctly on screen, but, once you refresh they disappear. Oddly (and interestingly) there are no errors in Stackdriver.
Visually this is what is happening. Both of these images were created when running the same script with the same input for two different forms:
As you can see, the first one is created and has 4 options, the second is created and has just 1 option.
It happens frequently, but not all the time. Seems like it almost has to be a Google bug, but, I've searched their tracker and no one has reported anything.
I'll show our "choice creation code" in case it points to anything, but, the fact that we get different results with exactly the same input suggests there's something else going on.
I'm just showing one part of a loop, but like I said, the code isn't erroring at all. Is there an approach to creating large (30 question) Google forms which is better than running an apps-script plugin? I wish there was an API :(
Anyway, if this is a know issue, or there's a workaround, I'd love to hear it.
var item = form.addMultipleChoiceItem();
item.setPoints(points);
if (data.answer_sheet) { item.setTitle("Question " + position) }
var choices = [];
for (var i=0; i < question.count; i++) {
choices.push(item.createChoice(String.fromCharCode(65 + i), i+1 == question.correct));
}
item.setRequired(required);
item.setChoices(choices);
If you copy the following script into a google-apps-script environment and run the script, it should import a 30 problem multiple choice document. It will look as if everything has been imported correctly, then refresh the form and you will find that choices are missing. The code is below, I have also made a gist of it on github
function onOpen(e) {
FormApp.getUi()
.createAddonMenu()
.addItem("Add Questions to Blank Quiz", "processUpload")
.addToUi();
}
function onInstall(e){
onOpen(e);
};
function processUpload() {
var form = FormApp.getActiveForm();
var ui = FormApp.getUi();
// Delete all items in the form
var items = form.getItems();
while(items.length > 0){
form.deleteItem(items.pop());
}
createTest("ignored", true);
}
function questionUrl(url) {
if (url.lastIndexOf("https:", 0) !== 0) {
return "https:" + url;
} else {
return url;
}
}
function fetchImages(questions) {
let urls = questions
.map(q => questionUrl(q.url))
let imageResponses = UrlFetchApp.fetchAll(urls);
return imageResponses.map(e => e.getBlob());
}
function createTest (url, required) {
var data = sampleData();
var form = FormApp.getActiveForm();
form.setIsQuiz(true);
form.setTitle(data.title)
// don't want shuffling since image items are separate from answers
form.setShuffleQuestions(false);
let questionImages = fetchImages(data.quiz.questions);
data.quiz.questions.forEach(function(question, index) {
var position = question.position || index + 1;
var points = question.points || 1;
var title = "Question " + position;
if (!data.answer_sheet) {
form.addImageItem()
.setImage(questionImages[index])
.setTitle("Question " + position)
}
if (question.type === "mc") {
var item = form.addMultipleChoiceItem();
item.setPoints(points);
if (data.answer_sheet) { item.setTitle("Question " + position) }
var choices = [];
for (var i=0; i < question.count; i++) {
choices.push(item.createChoice(String.fromCharCode(65 + i), i+1 == question.correct));
}
item.setRequired(required);
item.setChoices(choices);
} else {
var item = form.addTextItem();
if (data.answer_sheet) { item.setTitle("Question " + position) }
item.setPoints(points);
item.setRequired(required);
}
});
}
function sampleData() {
return {
"answer_sheet": false,
"quiz": {
"questions": [
{
"correct": 4,
"count": 4,
"points": 1,
"position": 1,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 2,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 3,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 4,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 5,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 6,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 1,
"count": 4,
"points": 1,
"position": 7,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 8,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 9,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 10,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 11,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 1,
"count": 4,
"points": 1,
"position": 12,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 13,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 14,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 15,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 1,
"count": 4,
"points": 1,
"position": 16,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 17,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 18,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 19,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 20,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 21,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 22,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 23,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 24,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 25,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 26,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 27,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 3,
"count": 4,
"points": 1,
"position": 28,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 4,
"count": 4,
"points": 1,
"position": 29,
"type": "mc",
"url": "//via.placeholder.com/468x100"
},
{
"correct": 2,
"count": 4,
"points": 1,
"position": 30,
"type": "mc",
"url": "//via.placeholder.com/468x100"
}
]
},
"title": "30 problem doc"
}
}
Had the same issue. Simple fix. Instead of this:
var form = FormApp.getActiveForm()
const students = ['Han S.','Luke S.','Yoda']
var pickYourName = form.addMultipleChoiceItem()
// RISK OF EMPTY CHOICES: DON'T SET CHOICEVALUES LAST
pickYourName.setTitle('Choose your name:')
pickYourName.setChoiceValues(students)
Simply swap the order of operations and set the title last., like this:
var form = FormApp.getActiveForm()
const students = ['Han S.','Luke S.','Yoda']
var pickYourName = form.addMultipleChoiceItem()
// HAD NO ISSUE DOING IT THIS WAY: CHOICES FIRST, THEN TITLE
pickYourName.setChoiceValues(students)
pickYourName.setTitle('Choose your name:')
Actually I have the same problem, I found a hacky way around it. Its complexity is high O(n^2), but it works.
Basically, I'm double checking every question got it's choices correctly.
const items = [];
for(var i=0;i<questions.length;i++) {
items.push(form.addMultipleChoiceItem());
}
for(var j=0;j<questions.length;j++) {
for(var i=0;i<questions.length;i++) {
var item = items[i];
if(item.getChoices()[0].getValue() === "A") continue; // already set question with choices, ignore it
item.setPoints(points);
if (data.answer_sheet) { item.setTitle("Question " + i) }
var choices = [];
for (var i=0; i < question.count; i++) {
choices.push(item.createChoice(String.fromCharCode(65 + i), i+1 == question.correct));
}
item.setRequired(required);
item.setChoices(choices);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With