Google Appscript VALUE not returned - google-apps-script

I'm a complete newbie to programming but wants to learn how. What I did is, I created a google form with 8 questions and the responses goes to a spreadsheet. Now what I want to do is to add another column on the spreadsheet, like a unique ID(should be a sequence like 10001, 10002, 10003, etc.) so I have a unique modifier, in that way once the form is submitted, that unique ID, will also increment by 1.
So far what I did is I created an array on the spreadsheet Unique ID column with this formula:
=arrayformula(if(row(A2:A)=1,"Unique ID",if(len(A2:A)>0,9999+row(A2:A),iferror(1/0))))
But, I don't know how to call the value on the google script editor. (example cell: I2 the value is 10001, I3 = 10002). Can you anyone help me with this please? Any help will be appreciated.

Getting your Id from the Form's Linked Sheet
function onFormSubmit(e) {
if(e.values && !e.values[1])return;//make question one a required question. This will keep you from sending emails due to spurious triggers.
var colnum='enter the column number of you id';//A=1,B=2...
var id=e.range.getSheet().getRange(e.range.rowStart,colnum).getDisplayValue();
}
Please note: You can not run a function like this from the Script Editor so to avoid the inevitable question I'll simply point out that this requires a trigger to test it. Or you have to figure out a way to provide it with an event object.
onFormSubmit Event Object

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.

Generating hyperlinks to prepopulate Google form

Context:
I created a Google Sheets/Forms workflow using sequential stages of Google Forms.
Form 1 (public facing) Accepts some data submitted by a public user and saves to Sheet 1.
Internal staff then contacts the submitter by telephone and conduct a more in-depth interview.
Form 2 (internally facing) is used by the interviewer to document
answers to the phone interview.
This question concerns the generation of Form 2 because I am partially pre-populating it with information from Sheet 1 (Form 1 submissions.) The way I figured out was to formulaically generate a URL with appended pre-population arguments e.g. "&entry.NNNNNN=whatever". I copied-down this formula in the last column of Sheet 1. Clicking on the cell and then the generated hyperlink successfully pre-populates Form 2 with data from the respective row of Sheet 1 as intended.
Problem: As soon as a new Form 1 submission is received, a new row is inserted into the Sheet 1 that does NOT contain the desired hyperlink formula in the last column. I would like that to be automatic so the interviewer is not responsible for performing a copy-down before every request for a Form 2.
I have pursued a couple of approaches to automating this:
One thread advised instead of copy-down, to create an arrayformula in the top cell so that it applies to the entire column including newly inserted rows as well. I tried every way I could think of but was unable to get my formula to produce a column of results with arrayformula(). If there is a way to fix this, that would be a satisfactory solution.
=HYPERLINK(CONCATENATE("https://docs.google.com/forms/d/e/XXXXXXXXXXXXXXXX/viewform?usp=pp_url&entry.251357138=",C2,"&entry.966351469=",D2,"&entry.384696201=",E2,"&entry.1366694528=",F2,"&entry.463407115=",M2,"&entry.1557144679=",B2,if(P2,"&entry.1777888516=Email",""),if(O2,"&entry.1777888516=Phone",""),if(H2,"&entry.2110474669=Individual+(Adult)",""),if(I2,"&entry.2110474669=Individual+(Under+18,+Minor)",""),if(J2,"&entry.2110474669=Couple",""),if(K2,"&entry.2110474669=Family",""),if(L2,"&entry.2110474669=Group",""),if(R2,"&entry.1892971721=San+Jose",""),if(S2,"&entry.1892971721=Sunnyvale","")), "Complete Intake")
I tried to create a ModalDialogue and display a script generated hyperlink in it. I used this approach found in this forum. But this did not open any dialog at all and threw no errors (even after hyperlink was removed.) There was no indication of pop-up blocking. Other parts of my script use Browser.msgBox without any pop-up troubles, but I don't think that will pass a hyperlink.
var htmlOutput = HtmlService
.createHtmlOutput('Click to open and prefill intake interview form.')
.setWidth(250) //optional
.setHeight(50); //optional
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Ready to fill intake interview form:');
Using onFormSubmit() and scripting a copydown after a new row has been inserted. But I have been unable to figure out how to identify which row was inserted into Sheet 1. I see some people using lastRow(), but it isn't always inserted into the last row - typically it goes in the middle somewhere.
Request:
Help getting arrayformula to work in my case.
Or help getting ModalDialog to display a script generated hyperlink.
Or help on how to identify the row the Form submission inserted. Or do I just need to make sure the table remains sorted by TimeStamp and then I can use lastrow()?
Suggestion for a cleaner approach to get to the same place (generating a prepopulated Form from a row of data in Sheet 1.)
Thank you for illuminating a path forward.
You should consider using ArrayForumlas to automatically copy down the formula to other rows that have a value in the first column.
Put this formular in row 2 of the column that has the Google Form links.
=ARRAYFORMULA(
IF(ISTEXT(A2:A),
HYPERLINK(
CONCATENATE(
"https://docs.google.com/forms/d/e/XXXXXXXXXXXXXXXX/viewform?usp=pp_url&entry.251357138=",C2:C,"&entry.966351469=",D2:D
)),""))
I wrote a tutorial on copying formulas if you need more examples.
It turned out I was able to successfully employ approach 2, the modalDialog. For some reason no dialog was appearing when I first attempted so I didn't know if there was something fundamental wrong with this approach. I tried again and it worked as shown below so I suppose I just had some typos. Adding target="_blank" was helpful so as to open in a new tab.
var htmlOutput = HtmlService
.createHtmlOutput('Click to open and prefill intake interview form.')
.setWidth(250) //optional
.setHeight(50); //optional
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Ready to fill intake interview form:');

Workaround for not losing cell's reference because of user doing sorting, while script checks cells value

I have been struggling with the following situation for almost the whole last week and it would be awesome if someone could give me some hint.
The situation:
1. Script finds a particular value in, lets say, 'Sheet1', and gets the row number of the cell containing this value.
2. Since script has found this value, it executes a bunch of actions like creating new spreadsheet and copying numerous 'Sheet1' from dozen other spreadsheets to this newly created spreadsheet, and comparing/ analyzing data.
The problem.
- While script is doing a bunch of other actions, user is able to rearrange cells by, for example, sorting A to Z, which changes the address of previously found cell.
Here is the code that I used in order to verify this:
function WhatHappensIfUserSorts () {
var ss = SpreadsheetApp.getActive();
var sh = ss.getActiveSheet();
var rng = sh.getRange("B17"); //Lets say that script finds this cell according to some rules
Utilities.sleep(10000);
rng.setValue("Test Value");
}
Question:
Might there be any workaround for this?
My current ideas.
1. I was thinking about hiding the filter row in the beginning of the script, but this doesn't help a lot, because users can insert new row in the which will change the addresses of the rows below.
The background.
I am trying to create two way synchronization, meaning, each project member has his/ her own spreadsheet with 'Project X', 'Project Y' etc. sheets and no matter who updates their project sheets, all other users that work on the same project get these updates in their project sheets. These updates that have to be tracked are not just the cell values, these are cell notes as well. And this is the reason why script has to do the bunch of other actions, since CopyTo method does not work between spreadsheets.
During my research I found sheetSpider project, but it seems somewhat different and too complicated from what I need.
A simple suggestion would be to give each row a unique identifier so that you could use it to evaluate the target range again before you write back to the sheet.
get target row's unique ID --> do work --> locate target rows ID and use to determine write range --> write back to sheet.
Alternatively, during the operation you could delete the target row and then use appendRow() to drop the updated version back in.
A third and final suggestion might be to temporarily suspend the permissions for the sheet. See: https://developers.google.com/apps-script/reference/spreadsheet/page-protection#setProtected

How query/search for information from one Google spreadsheet to another spreadsheet using GAS?

I would like to create a Google Apps Script to do the following: When I select a cell containing the name of a person in a spreadsheet (a spreadsheet that records sales, for example), and use a menu button to call the function, the script does a search (a query) using the person's name (or number of his document) in another spreadsheet that stores complete consumer data and that contains all the information that I need from that consumer to generate a contract or a payment receipt.
What is the best strategy to implement this search for information from one spreadsheet in another spreadsheet using Google Apps Script?
Do you have some script sample with a implementation similar to this? THANK YOU in advance for any help/guidance!
There is no event triggered by a cell selection, you'll have to use a menu item or a button to call the function or, if it is acceptable for your use case, edit the cell to trigger an onEdit event.
The 'search part' is actually very simple, the data being on the spreadsheet itself or in another one has no importance, it will simply change the way you access data ( getActiveSpreadsheet or openById()). From there just get all the values and do a search in the resulting 2D array.
EDIT following your comment : here is an example of such a code that returns the range of the found cell (and we get the A1 notation but we could getValue() as well of course.).
function test(){ // to test the find function with an argument, 'any' in this case
var result = findItem('any');
if(result){Logger.log(result.getA1Notation())}else{Logger.log('no luck !')};
}
function findItem(item){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = ss.getDataRange().getValues()
for(var n = 0;n<data.length;++n){
if(data[n].indexOf(item)>-1){ // this is a "strict" find, ie the value must be the entire search item. If you want to do partial match you should compare differently...
return (ss.getRange(n+1,data[n].indexOf(item)+1)); // if found return the range. note the +1 because sheets have 1 index while arrays have 0 index
}
}
return false;// if we come to the end of sheet without result...
}

Questions about data formatting using UiApp and google spreadsheet

Thank you in advance for any help you can provide. As background, I built a simple UiApp using GAS that I use to populate a google spreadsheet and a calendar with entries about events including time, date, location, etc. I've had it working for awhile but I want to keep improving it and I have a few questions about format and functionality.
1.) I now want the script to copy the information to a second spreadsheet, I've established how to do this, but the second spreadsheet already has some columns in use that I don't want to override and I don't want to just place the info from this Ui into the first 'X' number of columns, is there any easy way to essentially "copy these 5 columns to the first then skip and column and bring in the rest". Here is the code I have for the copy action right now:
var ss = SpreadsheetApp.openById(ssID);
var sheet = ss.getSheets()[0];
sheet.getRange(sheet.getLastRow()+1, 1, 1, 20).setValues([[new Date(), eventTitle, eventDateFrom, eventStartTimeb, eventEndTimeb, eventLocationName, eventLocationCity,eventActivity, eventLeadContact, eventNSLContact, eventContactAttending, eventDepartment, eventStaff, eventMaterials, eventCost, eventIncentive, eventMSTarget, eventSolar, eventNotes,eventRegion]]);
Also, in the same vein as this question, I've been wondering if it is possible to write something that will choose when an entry is copied to the second spreadsheet based on the value of one of the elements. For example, if eventStaff=0 or is blank, the script will copy the designated information to first spreadsheet but not the second.
2.) Date format: I added two listboxes for to capture event time start and event time end and I would like them to show up in the spreadsheet formatted as 00:00 AM/PM, but have only accomplished to get 00:00:00 or whole number so far.
3.) Using multiple elements to fill the location and events portion of calendar entries. This script works to create a basic event with start/end time and a title, but I'd like to use some of the information to fill in the location and description of an event. Is there a way for me to do this or do I need to concatenate those fields into one in able to enter them in the event creation. Current event creation code:
cal.createEvent(eventTitle,eventDateFrom,eventDateTo);
Sorry for the wall of text, if any clarification/additional code sample is needed just ask. Thank you in advance for any help/insight you might be able to provide.
Please don't be offended but I'm afraid your questions are more general programming question than GAS question, by formulating the question you almost answer it by yourself (question 1).
As for question 2, have a look to Utilities.formatDate and you'll get what you want, see also this.
Question 3: see CalendarApp documentation, createEvent, there is a set of optional arguments that suits your needs. - best regards,