tracking editing values from Google Form - google-apps-script

I've a google form, and I split data based on sections. I've 3 sections for example and data is get separated into 3 different sheets when user submits the form, I've successfully done it using form events, but now I want to know how I can track changes if user edits the form and make those fields red.
Sorry I am not including the code, here just want to know about suggestion to do it?
Can you suggest methods I can use for this?

Get response id:
Assuming you are using an onFormSubmit trigger (for Forms, not for Sheets), you can use the corresponding event object to get information about the form response.
More specifically, you can retrieve the form response id, which will be the same every time the form response is edited, as well as the different form item ids. You can use these field to identify the response in your sheet and each of the corresponding items and update those. For example, if this was your trigger function:
function onFormSubmit(e) {
const responseId = e.response.getId();
const itemResponses = e.response.getItemResponses();
itemResponses.forEach(itemResponse => {
const response = itemResponse.getResponse();
const itemId = itemResponse.getItem().getId();
// Find cells with corresponding responseId and itemId
// Update cells if found, populate new ones if it's a new submission
});
}
Find cells in spreadsheet:
Then you should find the responseId in your spreadsheet. You can use Range.getValues to look for the sheet values or, if you feel so inclined, use TextFinder to find the corresponding cell.
Update cells:
Once you've identified the cells, you can update the corresponding values (Range.setValues) and/or update the background color (Range.setBackgrounds).
Note:
This solution requires you to add the different responseId and itemId for every form response in your sheets. Otherwise, there will be no way to identify these whenever a response is submitted or edited.
The exact workflow for this would depend on the data structure you have, the form items you want to track, etc. I hope there's enough indications here to help you though.

Related

Can I update a Google Sheets spreadsheet using a Google Form?

I'm looking to store data about foster animals from a google form. Essentially, it will just input the information entered into the spreadsheet. This works well for the first submission, but is not useful for if I would like to change information recorded for a specific animal. I think name is my best bet for a unique identifier, so I figure that I would want to write a script that would search for the name through a given column if the same name was entered and then repopulate that row.
Is this even something I can do to begin with? In addition, am I thinking about it in a very backwards way? If more information is needed, I am happy to provide it.
The best approach in this situation is to make use of Apps Script triggers.
You could start by using an onFormSubmit which will run when a user ends up submitting the form needed.
This is an installable trigger which means that it will require a setup first.
If you plan on using the form for modifying the information, you can easily create an id field for instance in the form and setup a script something similar to this:
function onFormSubmit(e) {
let ss = SpreadsheetApp.openById('SS_ID').getSheetByName('SHEET_NAME');
let idCol = ss.getRange('ID_RANGE').getValues();
let submissions = e.namedValues();
for (let i = 0; i < idCol.length; i++) {
if (idCol[i][0] == submissions.Id)
//update the sheet accordingly
else {
//add the new values to the sheet
}
}
}
In order to gather the submissions from the form, the e.namedValues has been used. Assuming, you have a column in your spreadsheet in which you store the id of each animal which corresponds to an item in your form, you can simply check if the submitted form is addressed for an existing item - so you can update it with the new info or simply just add the new submissions to the sheet.
Please bear in mind that you will have to adapt this so it fits your current setup.
Reference
Apps Script Installable Triggers;
Apps Script Event Objects.

Sheets Script - Detect duplicate cell in same column and remove newest row with duplicate cell

I've looked around StackOverflow and also GitHub but I couldn't find a solution that seems to be simple enough. Here's the deal:
A form is used to input new clients into a sheet that contains all client details.
Accidentally, account managers sometimes "open" the same client twice (always using the same form which feeds to the same sheet).
I don't want to mess with the script of the actual form and I'm OK if the form will submit anyway, without checking anything prior to hitting the submit button.
After each submission, I run an onFormSubmit script. I want to use that script to detect such duplicate clients and delete the last entry, i.e. row with the most recent timestamp.
I understand that client name, addresses, and other string fields can sometimes enter with slight variations so my duplicate search will rely on the client ID number. Sure, typos can also happen with the ID but this is the safest option to detect duplicates.
Once removed, I'd like to send an email to a specific address (group). In the email, I'd like to list the ID number which was detected as a duplicate, along with the email of the user which inputted this duplicate, i.e. email of the last person to submit this duplicate. My form catches emails so they're logged into the Sheet anyway but that row will be deleted and I want to catch this email prior to deleting it with this script.
I don't have a sample code to place here as I couldn't find that was simple enough, or that hasn't fiddled with the actual form.
Any ideas for a simple yet effective script that only "touches" that single sheet?
This is not exactly what you want but it does not allow rows to be append that have duplicate ClientID's and you can redefine what the client ID is and it get the rest of the headers from e.named.Values; You can also position them in any order that you wish.
function dontAllowDuplicateClientIds(e) {
const idhdr="ClientID";
const hA=Object.keys(e.namedValues).filter(function(e){return e;});
hA.splice(hA.indexOf('Timestamp'),1);
Logger.log(hA);
if(hA.indexOf(idhdr)==-1) {
Logger.log("Invalid idhdr Assignment");
return;
}
const ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Non Duplicate Client Id Sheet2');
if(!sh) {
sh=ss.insertSheet('Non Duplicate Client Id Sheet2')
sh.appendRow(hA)
}
const hdrA=sh.getRange(1,1,1,sh.getLastColumn()).getValues()[0];
const idx={};
const dA=[];
hdrA.forEach(function(h,i){idx[h]=i;dA.push(e.namedValues[h][0]);});
if(sh.getLastRow()>1) {
const vA=sh.getRange(2,idx[idhdr]+1,sh.getLastRow()-1,1).getValues().map(function(r,i){return r[0];});
if(vA.indexOf(e.namedValues[idhdr][0])==-1) {
sh.appendRow(dA)
}
}else{
sh.appendRow(dA)
}
Logger.log(dA);
}
In you want to run this manually you can do so with this:
function testnextfunction() {
var e={namedValues:{ClientID:"123abc",FirstName:'J',LastName:'Cooper',MiddleName:'B'}};
dontAllowDuplicateClientIds(e);
}
I'd like to believe I'm not the only super-novice here. For my fellow beginners, here's a simple code that uses a status-indicator cell to find a duplicate.
First, let's remember that the form is submitted either way, not checking anything on the form itself. here are some basic stups:
1. we sort the sheet by defending order of the timestamp column.
2. On cell Z2 I added the following function: =match(F2,F3:F1000,0).
** In my case, column F holds the client ID, for which I want to search for duplicates.
4. Here's a simple code to wrap it up:
function searchduplicate () {
var clientid = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("רשימת לקוחות").getRange('Z2').getValue();
// var noduplicate = "N/A"
if (clientid === "#N/A") {
Logger.log("no duplicates")}
// plus any other actions to run if no duplicates
else {
Logger.log("duplicate")}
// plus any other actions to run if there ARE duplicates
}

Create a response table with a Google sheet which saves responses in another sheet

I'm trying to create a response table with a Google sheet that lets people enter their responses. Then compile that information into another Google Sheet by specified columns at the bottom of the previous response.
I have tried numerous ways but I cannot seem to get the script to work.
Broken Down, I need the Script/Guide to be able to:
Allow multiple people to record their response individually by the given link of Google sheet Form
Give a dynamic Sum Total in the Total Row
Have an Add row Icon so as to let respondent add rows dynamically and make their own choice of inputs
Create a Submit Icon, which records the response to another google sheet
The intended sheet is below
https://docs.google.com/spreadsheets/d/1cQTBONtpLiMbRmtVgSyOT_mShzzwbrX7-w46zy9w9I4/copy?usp=sharing
This may be a simple question that I didn't sound any solution
Please see if this works for you.
Modified enquiry form
1. Allow multiple people to record their response individually by the given link of Google sheet Form
You need to share a copy of your spreadsheet. Do not share the original. In the URL you have posted, replace 'edit' with 'copy'.
The modified enquiry form
2. Gives a dynamic Sum Total in the Total Row as your user records their inputs by using onEdit function.
3. Has an Add row and Delete row Icon so as to let respondent add and delete rows dynamically and make their own choice of inputs. To add a row, the active row number should be 4 or above
4. Creates a Place Order Image, which appends the response to another google sheet
To achieve point 4, you need to create a separate spreadsheet having 1 row only. This serves as the column heading and can be in a form as shown below. This spreadsheet contains the details of responses from all users.
Note: Updating a spreadsheet automatically when the user clicks the Submit button would require you to make the spreadsheet shareable via email addresses with editor access at a minimum. This is potentially an unsafe way of saving user responses.
function sendData() {
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sprsheet.getActiveSheet();
var range = sheet.getRange("A2:G4");
var values = range.getValues();
var mainsprsheet = SpreadsheetApp.openById("main sheet id");
// 1. this "main sheet id" should say something like: "1cQTBONtpLiMbRmtVgSyOT_mShzzwbrX7-w46zy9w9I4", you can xopy/paste the id from your address bar in your browser
// ==> https://docs.google.com/spreadsheets/d/1cQTBONtpLiMbRmtVgSyOT_mShzzwbrX7-w46zy9w9I4/edit?ts=5ed39726#gid=0
var targetSheet = mainsprsheet.getActiveSheet();
targetSheet.appendRow(values);
// 2. appendRow() accepts an array like for example this array with strings ["Fabric Code", "Thickness","Width","Length","Finish","Quality type","Quantity"]
// method getValues() returns an array of arrays (or 2D array) like for example this one[["Fabric Code", "Thickness","Width","Length","Finish","Quality type","Quantity"]]
// Think of the outer [..] as row indicator and the inner [..] as the array that holds the columns(fields) of the record.
// i would change your code to: (remove the //s)
// var lr = targetSheet.getLastRow()
// var lc = targetSheet.getLastColumn()
// targetSheet.getRange(lr+1 , 1, values.length, values[0].length).setValues(values)
//Clear the cells (optional)
range.clearContent();
}

Calculated Value For Google Form Item Not Refreshing

I have been using the script suggested by Mogsdad here. I have hit a bit of a brick wall trying to use the timestamp as per my post here.
So, my approach now is to try to get a unique ID in to the form before submission so that I can use it in the form response feedback in to the sheet. I am try to force a list item to have a selection of one value via the below script -
function updateForm(){
// a way to get the items from the form
var form = FormApp.openById("1t4NG2KYk09YiVzeVypWKpYTiWN97VuLBibafKbKfzP4");
var seqList = form.getItemById(1050085080).asListItem();
var d = new Date();
var n = d.valueOf();
seqList.setChoiceValues([n]);
}
While this is indeed creating a unique value, and putting it on the form response sheet, when I go in to the form to create a new submission, the same ID number is still there. Any ideas on how I force that value to be recalculated each time the form is brought up ?
We don't have the very important thing. It's called like a pre-form action or a trigger or an automate action. You can't do that.
You need create your own Form to manage your data. Look at I need to create a Google form to check if data being entered already exists in sheet
Cheers!

Dynamically edit multiple choice options in live Google Form using Apps Script

I'm a high school teacher in L.A. trying to create a course registration system using Apps Script. I need the Google Form I'm using for this registration to:
Question 1) Update the choices available in subsequent multiple choice questions on new pages based on a student's current response choices.
Question 2) Eliminate choices from the form when a multiple choice option has reached it's "cap".
Question 1 Example)
A student registers for “tie-tying” in workshop 1, and gets taken to a new page. The Script edits the available choices on that new page based on the student’s first choice, and removes “tie-tying” from the list of possible choices on that new page, so “etiquette” is their only remaining option.
Question 2 Example)
Students can either register for “tie-tying” or “etiquette”, both responses are initially available in the Google Form. 30 students take the survey, all 30 register for the “tie-tying” workshop. The Apps Script references the response spreadsheet, realizes the “tie-tying” workshop is full, then removes it from the Google Form's list of possible choices. Student 31 goes to register, and their only option is “etiquette”.
If my question has already been asked and answered (believe me, I did search!) I'd appreciate the redirection.
I believe we can achieve your second objective without too much difficulty and modify the form, based on the current state of response.
The approach is to
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
For instance
function updateForm(e) {
if (e.values[1] == 'Yes') {
Logger.log('Yes');
var existingForm = FormApp.openById('1jYHXD0TBYoKoRUI1mhY4j....yLWGE2vAm_Ux7Twk61c');
Logger.log(existingForm);
var item = existingForm.addMultipleChoiceItem();
item.setTitle('Do you prefer cats or dogs?')
.setChoices([
item.createChoice('Cats'),
item.createChoice('Dogs')
])
.showOtherOption(true);
}
}
When it comes to achieving the goal in your first question, its more delicate, as the form will not submit mid way. What is possible is to go to different pages based on different responses to a Multiple Choice question, your use case may fit this method, although its not very dynamic.
Further its possible to use html Service to create completely dynamic experience.
Let me know if you need further information.
You are not able to create this type of dynamic form using the Google Forms Service, because there is no interaction between the service and scripts during form entry, except upon Form Submission. In the case of a multi-page form, a script has no way to know that a student has completed one page and gone on to another.
You could achieve this using the HtmlService or UiService, though. In either case, you'd rely on the client-side form interacting through server-side scripts to get updated lists of course options, then modifying the next 'page'. It will be complex.
The other answer to this question will keep adding a multichoice select each time for the form is submitted. Using similar approach of:
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
I've used the following code to modify a list select which could be easiliy modified for a multiple choice.
function updateForm(){
var form = FormApp.openById('YOUR_FORM_ID'); // Base form
// need to read what dates are available and which are taken
var doc = SpreadsheetApp.getActiveSpreadsheet();
var dates = doc.getRange("dates!A1:A10").getValues(); //available options
var taken_dates = doc.getRange("responses!F2:F51").getValues(); //just getting first 50 responses
// joining the taken dates into one string instead of an array to compare easier
var taken_dates_string = taken_dates.join("|");
var choice = [];
// loop through our available dates
for (d in dates){
// test if date still available
if (dates[d][0] != "" && taken_dates_string.indexOf(dates[d][0]) === -1){
choice.push(dates[d][0]); // if so we add to temp array
}
}
var formItems = form.getItems(FormApp.ItemType.LIST); // our form list items
// assumption that first select list is the one you want to change
// and we just rewrite all the options to ones that are free
formItems[0].asListItem().setChoiceValues(choice);
}