google-sheetsgoogle-apps-scriptgoogle-forms

Casting method asTextItem throws error for Google form item


This code is to make sure that the item can be operated as correct type in Google form. This code throws TypeError: item.asTextItem is not a function at the line return item.asTextItem();. It seems to me that you can ONLY go into that line by being the correct item type. What could be the problem or solution?

function createFormItem_(form, itemData, config, indices, questionCount) {
  const itemHandlers = {
    'Single': createSingleChoiceItem_,
    'Multiple': createMultipleChoiceItem_,
    'ShortAnswer': createShortAnswerItem_,
    'DateOnly': createDateItem_
  };

  // Get the base type (handle Multiple variants)
  const baseType = itemData[indices.itemType].split(/\d+/)[0];
  const handler = itemHandlers[baseType] || createDefaultItem_;
  const item = handler(form, itemData, config, indices);
  
  return item;
}

function createShortAnswerItem_(form, itemData, config, indices) {
  const item = form.addTextItem();
  const validationType = itemData[indices.validationCol];
  
  const validations = {
    'Email': createEmailValidation_,
    'PhoneNumber': createPhoneValidation_
  };
  
  if (validationType in validations) {
    const validation = validations[validationType]();
    item.setValidation(validation);
  }
  
  return item;
}
function updateQuestionItem_(form, config, row, cols, existingStructureArr, questionCount, position) {
  const itemId = row[cols.id];
  const oldItemIndex = existingStructureArr.indexOf(itemId);
  
  let item;
  if (oldItemIndex >= 0) {
    const oldTitle = existingStructureArr[oldItemIndex + 1]; //String stored as ID1;Title1;ID2;Title2 => TitleIndex == IdIndex + 1
    item = GetQuestionItemInFormByTitle_(oldTitle, form);
    form.moveItem(item, position - 1);
    
    isChoiceQuestion = item.getType() == FormApp.ItemType.MULTIPLE_CHOICE || item.getType() == FormApp.ItemType.CHECKBOX;
    if(isChoiceQuestion) applyChoices_(item, row, cols, config);
  } else {
    item = createFormItem_(form, row, config, cols, questionCount)
  }

  applyCommonProperties_(item, row, cols, questionCount);
  return item;
}


function applyCommonProperties_(item, itemData, indices, questionCount) {
  const title = isNumbered ? 
    `${questionCount}. ${itemData[indices.questionCol]}` : 
    itemData[indices.questionCol];

  item = ConvertGeneric2SpecificItem_(item);
  item.setTitle(title)
      .setRequired(itemData[indices.requiredCol])
      .setHelpText(itemData[indices.itemGuide]);
}

function ConvertGeneric2SpecificItem_(item) {
  try {
    switch (item.getType()) {
      case FormApp.ItemType.MULTIPLE_CHOICE:
        return item.asMultipleChoiceItem();
      case FormApp.ItemType.CHECKBOX:
        return item.asCheckboxItem();
      case FormApp.ItemType.LIST:
        return item.asListItem();
      case FormApp.ItemType.TEXT:
        return item.asTextItem();
      case FormApp.ItemType.PARAGRAPH_TEXT:
        return item.asParagraphTextItem();
      case FormApp.ItemType.DATE:
        return item.asDateItem();
      case FormApp.ItemType.TIME:
        return item.asTimeItem();
      // Add more cases for other item types as needed
      default:
        Logger.log(`Invalid item type: ${item.getType()}`);
        return null;
    }
  } catch (error) {
    Logger.log(`Error converting item: ${error.message}`);
    return null;
  }
}

Solution

  • Here is my "answer" for the "bug" encountered at the question. The purpose of the method was to make sure it's the correct ItemType before the code does anything with it.

    I spent a lot of time tracking each item/variable line by line to see what happens to them but found nothing wrong. (The debugging in App Script is terrible). I came to the conclusion that Google actually does NOT give the method to cast the specific item type as that same type for some item types (for me specifically MULTIPLE_CHOICE and TEXT). So my "solution" was ignoring the error and move on using the original item. And it works fine as of 31 Oct 24. This is the method.

    function ConvertGeneric2SpecificItem_(item)
    {
      try
      {
        switch(item.getType())
        {
          case FormApp.ItemType.MULTIPLE_CHOICE:
            return item.asMultipleChoiceItem();
          case FormApp.ItemType.CHECKBOX:
            return item.asCheckboxItem();
          case FormApp.ItemType.LIST:
            return item.asListItem();
          case FormApp.ItemType.TEXT:
            return item.asTextItem();
          case FormApp.ItemType.PARAGRAPH_TEXT:
            return item.asParagraphTextItem();
          case FormApp.ItemType.DATE:
            return item.asDateItem();
          case FormApp.ItemType.TIME:
            return item.asTimeItem();
          // Add more cases for other item types as needed
          default:
            Logger.log("Invalid item type. Return original item.");
            return item;
        }
      } catch (error) {
        Logger.log(`Error converting item: ${error.message}. Return original item`);
        return item;
      }
    }