Create and update time in google form responses - google-apps-script

Is there away to get google form (response) submit time and update time?
I have created google form and responses are being recorded in Google sheet. As soon as response is submitted it automatically captures time under first column that is "Timestamp". Now, if the response is updated ( for an example after three hours) then the time recorded initially (Timestamp) also gets updated. By the way i have created script which generates link to edit response in last column so that users can update their responses anytime. Is there any work around to get response submitted (created) time and update in different columns?
Any help is appreciated.
As suggested by Ruben,
I've created below script but it is not working
function assignEditUrls() {
var form = FormApp.openById('1UoHiwgl2Kw6RK5c7-
0kp1iFP0CPPR_LDbvSm1hw9xLg');
var sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form
responses 1');
var data = sheet.getDataRange().getValues();
var urlCol = 16;
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j]
[0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol,
resultUrls.length).setValues(resultUrls);
{
var blankRow=sheet.getLastRow(); //identify the next blank row
// date function to update the current date and time as
submittted on
var value = sheet.getRange(blankRow, 19).setValue(new
Date()).setNumberFormat('dd-mm-yyyy h:mm:ss'); //Submitted On
sheet.getSheetValues(value);
}
}
It is updating time in the last column, but if I update the form response then again it gets updated. I want create date which should be entered in the initial entry. Please help me with the correction in my script.

There is no built-in way to do that.
One option is that you use your script that adds the URL to edit the form response to also add the timestamp to another column when a new form response is submitted and to another column when the form response is edited.
Related
How to check if current submission is editing response or a new response

Related

Why does updating a form cause onFormSubmit trigger to run?

My code here:
function script1(){
//What is the form and data item ID?
var form = FormApp.openById("Form ID");
var namesList = form.getItemById("Item ID").asListItem();
//What sheet is used to update the form?
var ss = SpreadsheetApp.getActive();
var names = ss.getSheetByName("Update");
// Grab the values in the sixth column of the sheet - use 2 to skip header row
var namesValues = names.getRange(2, 6, names.getMaxRows() - 1).getValues();
var departmentNames = [];
// Convert the array ignoring empty cells
for(var i = 0; i < namesValues.length; i++)
if(namesValues[i][0] != "")
departmentNames[i] = namesValues[i][0];
// Populate the drop-down
namesList.setChoiceValues(departmentNames);
}
appears to triggers the form to submit causing problems. I have an onFormSubmit trigger set up to copy the data to a database and then delete the row. Unfortunately, the headers keep getting copied to the database since the form does not actually send any data and the only row with data is the headers. How can I update the form without the form submitting? Screenshot example is included below.
[
I hope I was able to make myself clear. Thank you for any help.
Modified Screenshot
Here is a screenshot of the trigger and its executions.

Google form to create two rows based on a question response

I am creating a google form to capture data from multiple users. This form has 13 fields. 3 of the form fields are drop down which are populating data from a sheet. This part of the code is completed. But I got struck with the following scenario.
One of the fields captures instance details (production, UAT) and has checkbox option. I thought I would be able to create two rows in the response sheet when instance field has select on two check boxes but learnt that’s not how google form works. So I am looking for a scripting option to do the following.
When the user select PRD and UAT for the instance, two rows to be created in the form response sheet on when the form is created.
The data for the new rows created in #1 will remain the same for the two rows expect for the column instance which will adopt the checkbox value from the form in the respective rows.
If only one option is selected then only one row is added to the response sheet
My experience in google app scripting or Java is very limited. With my limited knowledge I was able to get the responses from the form but not sure how to create an additional row when the condition is met (as mentioned above). Taking one step at a time to understand the form architecture
Code 1:
This is to get the title, index and type of the fields in the form. So I know some information of the form (still learning)
function testgetFormDetails()
{
var form = FormApp.getActiveForm();
var items = form.getItems();
for (var i in items)
{
Logger.log(items[i].getTitle() +', ID - '+
items[i].getId() +', Type - ' +
items[i].getType() +' , Form Index - '+
items[i].getIndex());
}
}
Following is the execution log
**Execution log**
5:49:38 PM Notice Execution started
5:49:39 PM Info Business Group, ID - 286404828, Type - CHECKBOX , Form Index - 0
5:49:39 PM Info Instance, ID - 1043278952, Type - CHECKBOX , Form Index - 1
5:49:40 PM Notice Execution completed
Code 2:
Get responses for the questions (small progress)
function getResponseForInstance()
{
var formResponses = FormApp.getActiveForm().getResponses();
Logger.log(formResponses.length);
for (var i = 0; i < formResponses.length; i++)
{
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++)
{
var itemResponse = itemResponses[j];
var lookfor = 'UAT,PRD'
if(itemResponse.getResponse() == lookfor )
{
Logger.log('Question:' + itemResponse.getItem().getTitle() + ' Response:' + itemResponse.getResponse() )
}
}
}
}
The execution log shows me the row number, question and the response
**Execution log**
8:22:18 PM Info Question:Instance Response:UAT,PRD
8:22:18 PM Info Question:Instance Response:UAT,PRD
Now I have to marry both to create an additional row in the response spreadsheet and have been racking my brains on this. All I know atm is the **Logger.Log()** line will be replaced by additional code to add 2 rows when the condition is met.
Any help on this will be very much appreciated.
Look forward to your support and guidance.
Adding example screenshots per #Jose Vasquez
Sample Form
Actual Form Response
Expected Response - row two has been split into 2 row with column data in C2 is parsed into PRD and UAT per row and the reminder of the data remains the same for line 2 and line 3
OnFormSubmit Function results
Thanks
Al
You can split into different rows by filtering afterwards
Here's my approach (No triggers, only run and process all the current responses):
function processResponses() {
var ss = SpreadsheetApp.openById("SPREADSHEET_ID");
var sheet = ss.getSheetByName("SHEET_NAME");
const formResponses = FormApp.getActiveForm().getResponses();
for (var i = 0; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
// Add responses comma-separated included
var rowData = itemResponses.map(item => item.getResponse().toString());
rowData.splice(0, 0, formResponse.getTimestamp()); // Timestamp
// Split into different rows afterwards
if (rowData[2].includes(',')) {
rowData[2].split(',').forEach(instanceName => {
let tmpRow = rowData.map(data => data);
tmpRow[2] = instanceName;
sheet.appendRow(tmpRow); // Append to the sheet
});
} else {
sheet.appendRow(rowData); // Append to the sheet
}
}
}
First of all open the Spreadsheet where you'll store your responses. Having done that, iterate through your responses as you were already doing and then add all of your responses including the timestamp for each form response.
After adding the response data into rowData you can evaluate if the Instance Column (column 2 or Column C) includes a comma. If so, simply split this field by this character and then iterate through this data in order to append a new row into your sheet for each "instance".
On Form Submit trigger (keep in mind that you have to install it)
Retrieve the response from the Event Object.
function onFormSubmit(e) {
var ss = SpreadsheetApp.openById("SPREADSHEET_ID");
var sheet = ss.getSheetByName("SHEET_NAME");
// Form Response retrieved from the event object
const formResponse = e.response;
var itemResponses = formResponse.getItemResponses();
// Add responses comma-separated included
var rowData = itemResponses.map(item => item.getResponse().toString());
rowData.splice(0, 0, formResponse.getTimestamp());
// Split into different rows afterwards
if (rowData[2].includes(',')) {
rowData[2].split(',').forEach(instanceName => {
let tmpRow = rowData.map(data => data);
tmpRow[2] = instanceName;
sheet.appendRow(tmpRow); // Append to the sheet
});
} else {
sheet.appendRow(rowData); // Append to the sheet
}
}
References
FormResponse.getTimestamp
Sheet.appendRow

retrieve google forms edit urls and maintain existing data structure

I am interested in making some alterations to a snippet of the code that allows you to record URLs to edit Google Form's responses.
What I wish to achieve is a repeatable automated process of receiving those URLs upon form submit. However, one condition that I want to follow is to have those URLs pasted in the first column of the spreadsheet, maintaining the integrity of existing data in the following columns.
I think it is the only viable option for me, as the form is still in the development stage, and may receive more variables as the time progresses.
I have attempted:
Manually inserting a column in the Responses' Google Sheet and then try to setup the assignEditUrls{} function, but it yields no results.
Using a one time mini-function to insert the left most column, and then run the code. Also produced no results, unless it was included in the main function, which then inserts the leftmost column every time there is a submission.
Here's that:
function insertLeftMostColumn(){
//insert a column before the first one
sheet.insertColumnBefore(1);
//rename the header for the new column
var cell = sheet.getRange("A1");
cell.setValue("columnName");
}
This is the function.
function assignEditUrls() {
var form = FormApp.openById('1cg7bGRQjsv91sSCjYCwNJyoB3wN_MZ_9raV3tP3v1MA');
//enter form ID here
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 1');
var lastColumn = sheet.getLastColumn(); // This logs the value of the very last column of this sheet (without the values)
//Change the sheet name as appropriate
var data = sheet.getDataRange().getValues();
var urlCol = 5;
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
}
current result
expected result
If my understanding is right, you want to know how to insert the edit URLs in the first column instead of the last one.
If so, you need to implement some small modifications in your code:
Insert an empty column into the sheet, e.g. with the function insertLeftMostColumn(), as you intended above. Keep in mind that if you want to run the function only once, it needs to be called separately from assignEditUrls(), so you have to define sheet one more time within the function
urlCol is the column number, where the URLs shall be pasted. To change the column to the first one, modify var urlCol = 5; to var urlCol = 1;
data[j][0]?urls[timestamps.indexOf(data[j][0] tries to find timestamps in the first column.
Given that you inserted an empty column and the timestamps have been shifted to the second column - you need to change the code to data[j][1]?urls[timestamps.indexOf(data[j][1];
If you want the new URLs to be inserted every time upon form submit, you need to incorporate into your assignEditUrls() function a Form Submit trigger. Here you can find information about how to incorporate installable triggers.

Using insertText to edit a google form response on google sheet

I have a form that stores responses in a google sheet and what I'm trying to do is on form submit, I want to add or insert a text to a column to turn the response to a hyperlink. For example the response is 123456, I need to convert it to https://www.google.com/123456. I currently have this script but I'm getting an error on the insertText part.
var hyperlink = 'https://www.google.com/'
function onformsubmit(e){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 1');
var rg = sheet.getRange(1,3,sheet.getLastRow(),1);
var data = rg.getValues();
for(var i=0;i<data.length;i++){
var datstr=String(data[i][0]).insertText(0,hyperlink);
data[i][0]= (datstr);
}
rg.setValues(data);
}
Any suggestion will be much appreciated.
For the insert part I think what you want is this code in the for-loop:
for(var i=0; i < data.length; i++){
data[i][0] = hyperlink + data[i][0];
}
rg.setValues(data);
That will change all text in that column to include the modified hyperlink. If you want to just modify the new row whenever you submit a form response you'll need to access the values or range from the event argument (e), using e.range, e.values, e.namedValues or probably some combination. See the documentation here.

Code not applying a timely sheet edit

I have code in a spreadsheet with a trigger to run it on form submit. The code is supposed to first create a link to allow for editing the submitted form data. It has worked fine in older sheets, but in my latest iteration, it is not saving the link before proceeding.
This is the beginning of the code which is the function listed in the trigger:
function sendRegEmails(e) {
var emailSubject = templateSheet.getRange("B3").getValue();
var emailHTMLTemplate = templateSheet.getRange("B4").getValue();
var emailWSAddInToHTMLTemplate = templateSheet.getRange("B9").getValue();
var emailWSReqFormLinkHTMLTemplate = templateSheet.getRange("B10").getValue();
//Create and save the URL to allow the respondent to edit their registration
assignEditUrls(REGISTRATION_FORM_ID, REGISTRATION_SHEETNAME, REGISTRATION_LINK_COL);
Utilities.sleep(5000);// pause in the loop for 5000 milliseconds or 5 seconds to make sure the URL is in the worksheet
// Create one JavaScript object per row of data.
var objects = getRowsData(mainsheet);
// For every row object, create a personalized email from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {...(continues)
This code is in a different .gs file in the same project:
/**-----------------------------------------------------------------------------------
|
| Begin section to create link to editable form
|
------------------------------------------------------------------------------------*/
function assignEditUrls(PassedForm_ID, SheetName, urlCol) {
var form = FormApp.openById(PassedForm_ID);
var sheet = SpreadsheetApp.openById(REGISTRATION_SHEET).getSheetByName(SheetName);
var data = sheet.getDataRange().getValues();
var responses = form.getResponses();
var timestamps = [], urls = [], resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0]?urls[timestamps.indexOf(data[j][0].setMilliseconds(0))]:'']);
}
sheet.getRange(2, urlCol + 1, resultUrls.length).setValues(resultUrls);
}
When the email is sent the spreadsheet does not contain the URL. Has there been a change which would cause the assignEditURLs function to not save the URLs in the spreadsheet until after the other script is complete? Has something been added that I need to include in the code to get this to be added? I would like the email to go out within a couple minutes of the form submit.
As I said, this has worked in other spreadsheets. The only changes made to code has been to use the correct columns and files. The data ends up in the sheet, but not until after the email is sent.
REGISTRATION_FORM_ID = the ID of the Form file
REGISTRATION_SHEETNAME = the name of the sheet to receive the data
REGISTRATION_LINK_COL = the column number in REGISTRATION_SHEETNAME to place the data
REGISTRATION_SHEET = the ID of the Sheet file to receive the data
Regards,
Karl
On some scripts I maintain I've noticed with the transition to new sheets, the sheet ID changes. If you haven't already, try updating the REGISTRATION_SHEET variable with the new id.