I\'m working on a script that interacts with Google Form\' response sheet.
FormApp.getActiveForm().getDestinationId()
give me the spreadshe
I needed this also, and remarkably there is still no apps script method that facilitates it. In the end I set about finding a reliable way to determine the sheet id, and this is what I ended up with by way of programmatic workaround:
I'm sure some won't like this approach because it modifies the form and spreadsheet, but it does work well.
With the necessary wait times included it takes about 12 seconds to perform all the look up / clean up operations.
Here's my code for this method in case anyone else might like to use it.
// Takes Apps Script 'Form' object as single paramater
// The second parameter 'obj', is for recursion (do not pass a second parameter)
// Return value is either:
// - null (if the form is not linked to any spreadsheet)
// - sheetId [int]
// An error is thrown if the operations are taking too long
function getFormDestinationSheetId(form, obj) {
var obj = obj || {}; // Initialise object to be passed between recursions of this function
obj.attempts = (obj.attempts || 1);
Logger.log('Attempt #' + obj.attempts);
if (obj.attempts > 14) {
throw 'Unable to determine destination sheet id, too many failed attempts, taking too long. Sorry!';
}
obj.spreadsheetId = obj.spreadsheetId || form.getDestinationId();
if (!obj.spreadsheetId) {
return null; // This means there actually is no spreadsheet destination set at all.
} else {
var tempFormItemTitle = '### IF YOU SEE THIS, PLEASE IGNORE! ###';
if (!obj.tempFormItemId && !obj.sheetId) { // If the sheet id exists from a previous recusion, we're just in a clean up phase
// Check that temp item does not already exist in form
form.getItems(FormApp.ItemType.TEXT).map(function(textItem) {
var textItemTitle = textItem.getTitle();
Logger.log('Checking against form text item: ' + textItemTitle);
if (textItemTitle === tempFormItemTitle) {
obj.tempFormItemId = textItem.getId();
Logger.log('Found matching form text item reusing item id: ' + obj.tempFormItemId);
}
return 0;
}); // Note: Just using map as handy iterator, don't need to assign the output to anything
if (!obj.tempFormItemId) {
Logger.log('Adding temporary item to form');
obj.tempFormItemId = form.addTextItem().setTitle(tempFormItemTitle).getId();
}
}
obj.spreadsheet = obj.spreadsheet || SpreadsheetApp.openById(obj.spreadsheetId);
obj.sheets = obj.sheets || obj.spreadsheet.getSheets();
obj.sheetId = obj.sheetId || null;
var sheetHeaderRow = null;
for (var i = 0, x = obj.sheets.length; i < x; i++) {
sheetHeaderRow = obj.sheets[i].getSheetValues(1, 1, 1, -1)[0];
for (var j = 0, y = sheetHeaderRow.length; j < y; j++) {
if (sheetHeaderRow[j] === tempFormItemTitle) {
obj.sheetId = obj.sheets[i].getSheetId();
Logger.log('Temporary item title found in header row of sheet id: ' + obj.sheetId);
break;
}
}
if (obj.sheetId) break;
}
// Time to start cleaning things up a bit!
if (obj.sheetId) {
if (obj.tempFormItemId) {
try {
form.deleteItem(form.getItemById(obj.tempFormItemId));
obj.tempFormItemId = null;
Logger.log('Successfully deleted temporary form item');
} catch (e) {
Logger.log('Tried to delete temporary form item, but it seems it was already deleted');
}
}
if (obj.sheetId && !obj.tempFormItemId && !obj.tempColumnDeleted) {
try {
obj.sheets[i].deleteColumn(j + 1);
obj.tempColumnDeleted = true;
Logger.log('Successfully deleted temporary column');
} catch (e) {
Logger.log('Could not delete temporary column as it was still attached to the form');
}
}
if (!obj.tempFormItemId && obj.tempColumnDeleted) {
Logger.log('Completed!');
return obj.sheetId;
}
}
SpreadsheetApp.flush(); // Just in case this helps!
// Normally this process takes three passes, and a delay of 4.5 secs seems to make it work in only 3 passes most of the time
// Perhaps if many people are submitting forms/editing the spreadsheet, this delay would not be long enough, I don't know.
obj.delay = ((obj.delay || 4500));
// If this point is reached then we're not quite finished, so try again after a little delay
Logger.log('Delay before trying again: ' + obj.delay / 1000 + ' secs');
Utilities.sleep(obj.delay);
obj.attempts++;
return getFormDestinationSheetId(form, obj);
}
}