I have a google form. Every time it is submitted, the answers go into a google spreadsheet. I am trying to write an app script that triggers every time the form is submitted
The only line using: getResponses()
method is this one:
var responses = form.getResponses();
Your error:
Cannot call method "getResponses" of null
Means that form
is null. If form
is null, then this line:
//get the form
var form = FormApp.getActiveForm();
is not working. So, why isn't it working? There is nothing wrong with the code, so it must be a different problem. If there was an active form, that code would return a form
type. This means that there is no form bound to the script. getActiveForm()
Returns the form to which the script is container-bound.
Your script is not "container-bound" to the form. Your script is bound to the spreadsheet.
The documentation states:
To interact with forms to which the script is not container-bound, use openById(id) or openByUrl(url) instead.
You can bind your script to the form by opening the script editor from the edit page of the form. But, there's no need to do that if you want to keep your script bound to the spreadsheet.
The line var form = FormApp.getActiveForm();
isn't going to work in your spreadsheet script.
The problem with using the Event Object e
with an installable trigger, is that it looks like you can't get the response URL.
google_sheets_events
This means that you need to use openById(id)
or openByUrl(url)
inside the script bound to the spreadsheet, or move all your script to the form.
Here is how to get the edit url from script in the spreadsheet:
// Open a form by ID.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
Now the problem is, that you can only get the Edit Response URL: getEditResponseUrl()
through the "FormResponse" class. So you need the Form Responses.
var formResponses = form.getResponses();
But that's all the responses, you need the last one.
var lastResponseIndex = formResponses.length - 1;
var lastResponse = formResponses[lastResponseIndex];
var editURL = lastResponse.getEditResponseUrl();
or:
function getEditURLofLastResponse() {
// Open a form by ID.
var form = FormApp.openById('Your Form ID');
var formResponses = form.getResponses();
//get last respnse
var lastResponseIndex = formResponses.length - 1;
var lastResponse = formResponses[lastResponseIndex];
var editURL = lastResponse.getEditResponseUrl();
Logger.log(editURL);
}
Just an observation:
You are using an e
argument: function addeditlink(e) {
. But I don't see it being used in your code. That makes me wonder if you are using an "installable" trigger, as opposed to a "simple" trigger.
It's possible to get the values that were just submitted with e.values
or e.namedValues
. But you can't get the Edit URL with the Event Object.
I think you can only call FormApp.getActiveForm() from a script attached to a form, whereas your script is contained in a GSheet. I couldn't find a way to easily gets forms that used this sheet as its destination so what I've did was get all of the forms and then looked at the destination id of each and checked if it is the same as this spreadsheet. Once you've got your Form object you can get the responses. Feels a bit long winded would love to know if anyone knows a quicker way.
There are also a few exceptions that FormApp throws that you have to cope with.
Here's the function I use:
/**
* Find the first form that is linked to a specific spreadsheet
*
* @param {string} spreadsheet id
* @return {object} Form or null
*/
function getFormByDestinationId_(spreadsheetId) {
var formFiles = DriveApp.getFilesByType('application/vnd.google-apps.form');
var form;
var formFile;
var formId;
var destinationId;
while (formFiles.hasNext()) {
formFile = formFiles.next();
formId = formFile.getId();
// Throws an error if ID invalid
try {
form = FormApp.openById(formId);
} catch (error) {
if (error.name === "Exception") {
// Just ignore it
} else {
throw error;
}
}
// Form.getDestinationId() throws an error if there is no destination id
try {
destinationId = form.getDestinationId();
} catch (error) {
if (error.name === "Exception") {
// Just ignore it
} else {
throw error;
}
}
if (destinationId !== spreadsheetId) {
continue;
}
return form;
}
return null;
} // getFormByDestinationId_()
The solution is to remove:
var form = FormApp.getActiveForm(); //this is WRONG
and replace with:
var form = FormApp.openByID(' ID here ')
There is no "active form", because this script is being run in sheets, not forms.