Add custom Data to Google Sheet once Form is filled - google-apps-script

I am using a Goofle form that receives applications from users, once the form is submitted I am using Google form submission trigger to notify. It has some questions like (facebook profile link)
But while sending a notification I don't want those links to be appeared just the same way user enters, instead something like Facebook, twitter (text as hyperlinked.) should appear
I already know about onFormsubmit() function, but not sure how to use, help me out please.
For example:
Cell A2 has user submitted facebook profile link using the form.
I want Column B2 to automatically generated as =hyperlink(A2, "Facebook")
The same thing should happen like A3 to B3 whenever user submits a form.

Ok after a bit of digging and testing, I believe I got a solution for you since you use the "Yet Another Mail Merge" (aka YAMM) add-on. Here it goes:
Firstly make sure your Form is setup properly and linked to a Google Sheet. After all questions have been created, add another column to your sheet, and call it 'Hyperlink' or whatever you please (just remember it for later). We will make use of the form submit trigger in the script editor along with some code.
Here's the code:
function onFormSubmit(e)
{
var r = e.range;
var v = e.namedValues;
var link = v['Link'];
// For testing purposes, this part was apart of my form,
// I'd assume you'd want to change it to something more
// usable in your case. Notice that I refer to the values
// by the name of the question they preside in.
var friendlyName = v['Friendly Name'];
var rngHyper = getCellRngByCol(r, 'Hyperlink');
// See below for the meaning of the boolean
addHyperlink(rngHyper, link, friendlyName, true);
}
// Will only return one cell no matter the range size.
// Perfect for onFormSubmit(e) use case.
function getCellRngByCol(rng, col)
{
var aRng = SpreadsheetApp.getActiveSheet().getDataRange();
var hRng = aRng.offset(0, 0, 1, aRng.getNumColumns()).getValues();
var colIndex = hRng[0].indexOf(col);
return SpreadsheetApp.getActiveSheet().getRange(rng.getRow(), colIndex + 1);
}
// Add some form of hyperlink reference to one particular
// cell, passed as a range object
function addHyperlink(rng, link, name, useFormula)
{
if (useFormula)
{
// If useFormula is TRUE, use Google Sheet HYPERLINK formula,
// only if you are sure all URL's are formated properly,
// and include HTTPS/HTTP/WWW. Also looks more pleasing in Google Sheet.
var formula = '=HYPERLINK("<<URL>>", "<<NAME>>")';
formula = formula.replace('<<URL>>', link).replace('<<NAME>>', name);
rng.setFormula(formula);
}
else
{
// Else use HTML <a> tag with hyperlink referencing, which should transform
// any URL passed as a clickable hyperlink within email. Not very visually
// appealing in Google Sheet.
var value = '<<NAME>>';
value = value.replace('<<URL>>', link).replace('<<NAME>>', name);
rng.setValue(value);
}
}
Then set the trigger, which will probably ask for authorization after saving:
Next, save the script and then put in a test submission through your form to see that the link is created properly, or as desired. Afterwards clear the rows of the spreadsheet (not the header) and remove all responses of the Form itself (not necessary, but keeps things organized for testing purposes).
Now, install the YAMM add-on. It should then add a new column at the end of your sheet called 'Merge satus'. Before setting up the email notification on submit, we need to create your email template. Open up GMAIL, create an email with the desired fields and layout and save it as a draft. Here's what I did as an example:
I'm sure you're familiar with how this add-on, works so I shouldn't need to explain too much here.
After the draft has been created and saved, go back to the Google Sheet attached to the Form. Go to Add-ons > YAMM > Configure form submission notifications. I chose the 'Notify one or more addresses of all responses' option which are tied to the 'To:' emails preset in the draft. Select your draft from the drop down, fill in sender name if needed, AND (very important!!) check the 'Wait until a specific column is filled before sending the email' check box. Make sure to select the Hyperlink column (or whatever you chose to name it earlier). Here's my setup for reference:
Save it, test it, and ta-da. This simple formatting for hyperlinks has been resolved! :D

Related

Getting the value of a cell the user didn't exit

I have created a sheet in Google Sheets that is basically a form users fill out. They fill in the blanks, then press a button to run a script based on the data. However, no matter how I warn them, they don't exit the last field before clicking the button, and the script perceives that the last field is empty. I have tried letting the script activate another field on the screen, but it doesn't seal in the value before doing that. Is there another command that can force the value to be written to the field?
As an additional option to what Troy123 mentioned you can try the following script to detect blank values and display an alert if there is one before running the code you are using to submit the form.
Script:
function alertMessage() {
let ss = SpreadsheetApp.getActive().getSheetByName("Sheet2");
let lR = ss.getLastRow();
let lRValues = ss.getRange(lR, 1, 1, 3).getValues();
let x = false;
for(let i=0; i<3; i++) // Used 3 because I am just saving 3 values from code line 4
{
console.log(lRValues[0][i]);
if (lRValues[0][i]=="")
{
x = true;
}
}
if(x == true)
{
SpreadsheetApp.getUi().alert("Make sure there are no blank fields");
}
else
{
/*
Insert the form submission function or script here
*/
}
}
Example:
References:
alert(prompt)
Use a checkbox at the end of your form and have them click it. This checkbox does nothing, but it changes focus from the last field to the checkbox.
As suggested in a previous answer by Troy123, use a checkbox. IMHO this is the simplest option and by adding a very simple statement you could make your script to "reset" the checkbox, so it could "emulate" the button states, checked means pressed, unchecked means unpressed.
If order to make this able to work with scripts that requires more than 30 seconds to run, use an on edit installable trigger to call the a function responsible to responde to check/uncheck events.
function respondToCheckUncheck(e){
// Assing to a1Notation the reference of the cell containing the checkbox
const a1Notation = 'H10';
if(e.range.getA1Notation() === a1Notation && e.range.isChecked()){
// call here your function
myFunction();
// once the funcion finish, uncheck the checkbox
e.range.uncheck();
} else {
// do nothing
}
}
If you would like to take your script to a more sophisticated solution, your script could protect the cell having the checkbox and use the Lock Service to prevent other risks.
Using drawings to trigger Google Apps Script functions have several caveats like the one that was mentioned in this question
having a data entered in a cell and clicking the drawing when the cell is still in edit mode, will make that the value read from the cell doesn't match the value wrote.
While the workaround to check that the cell is not empty (see a previously posted answer by Fernando Lara) might help this still could lead to errors, i.e., if the user entered a value, pressed enter, but before clicking the button, edits the cell...
Considering the above, I suggest using other kind of element of the Google Sheets user interface, i.e. the Recorded Macros menu, a custom menu, a checkbox or cell with other data validation using a drowdown, a sidebar (requires the use of the HtmlService).
Other options to have in mind are to use a dialog for data entering created using the HtmlService, a Google Form or an AppSheet app.

Google-Sheets App Script to generate a custom email from inside Google Sheets

I have a google sheet which I use to send simple invoices. It is basic enough and it runs through an iPad (for fixed reasons) and this is the process which is kind of clunky :
-edit the template sheet which creates an invoice sheet (that's fixed obviously)
This is the awkward part :
-share/print/select one page (the invoice sheet)/print on a local printer
-share/print/select one page (the invoice sheet)/share (pdf) (edit mail)
I was wondering is it possible to have an apps script which :
-prints the first page of the sheets document, local printer
-opens the iPad mail program (not gmail)
-attaches the first page of the sheets document as a pdf
-changes the subject to a cell in the sheet (i.e. make the subject cell C1)
-changes the body to a cell in the sheet (i.e. make the body the contents of C2)
The question is strategic. If you have to control the final message version before sending, then use Gmail link to open "Compose window" with the corresponding parameters, as described here. Please note, you have no possibility to include any attachment by link in this case. You can (and should) do it manually.
Another way is to use templates (in drafts folder) which are more flexible for fill in data fields and for attachments too. The script can do your work completely but without the message preview. GmailDraft class has a useful getMessage() method for that and you can adjust details before sending. If you work with spreadsheets, you can adjust the script to show the message "preview" (similar to compose window) in sidebar or dialog window with a "Send" batton for confirmation.
Just in case, in addition to the strategic solution of Alexander Ermolin. As far as I know you can't print your documents in PDF via some printer. But you can make a PDF from spreadsheet pretty easy. Here is an example:
function myFunction() {
var ID = ''; // ID of your spreadsheet
var copy = DriveApp.getFileById(ID).makeCopy(); // make a copy of the spreadsheet
var ss = SpreadsheetApp.openById(copy.getId()) // open the copy
// convert all formulas into static values
var range = ss.getActiveSheet().getDataRange(); // get data range
var values = range.getDisplayValues(); // get all displayed values in the range
range.setValues(values); // paste the values back
while (ss.getSheets().length>1) ss.deleteSheet(ss.getSheets()[1]); // remove all sheets except the first one
DriveApp.createFile(ss.getBlob().setName('sheet.pdf')); // make a PDF file
copy.setTrashed(true); // delete the copy
}

Need to create dynamic hyperlink or change cell remotely

I've created a google spreadsheet. It has a master sheet, and I made a query function to pull data for my team.
My team has to update the column that has a comment section. But pulled data cannot be changed.
Now I need either of solutions:
1. Change the original cell in the master sheet remotely
2. Have a dynamic hyperlink to the cell they need to update
Here what I would want for the option №2 in my google spreadsheet - excel example I found on the internet
Solution
I believe this is what you were looking for (if not please clarify a bit more your question): you want to create a dropdown list that depending on the name on it the link next to it will change accordingly to direct you to the specific cell of that person in the other sheet.
If that is the case here is the simplified piece of code that will achieve this with self explanatory comments:
function onEdit() {
// Get the two sheets
var ss1 = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var ss2 = SpreadsheetApp.getActive().getSheetByName('Sheet2');
// Create an array for the dropdown list
var names = ['Ramon', 'Jose', 'Pepito'];
// Build the dropdown data validation
var dropdown = SpreadsheetApp.newDataValidation().requireValueInList(names).build();
// Set the dropdown to your desired ccell and attach the validation to that cell
var dropdownCell = ss1.getRange('A1');
dropdownCell.setDataValidation(dropdown);
// For every case of your dropdown (for every name) create an if condition so that the link on the side keeps changing
// accordingly to who is set on the drop down (i.e repeat this step for the rest of the names).
if(dropdownCell.getValue()=='Ramon'){
// Set the vale of B1 to the hyperlink formula (you need to get your linked sheet id and the range or cell you want to link it to.
ss1.getRange("B1").setValue('=hyperlink("#gid='+ss2.getSheetId()+'&range='+ss1.getRange('B112').getA1Notation()+'", "Click to jump to Sheet 2")');
}
}
For achieving this I took use of the formula hyperlink and of the Apps Script tool for creating data validation and setting it to a specific cell. Moreover, the use of onEdit() will allow you to catch instant changes in the dropdown cell.
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)

Google Forms: Is it possible to update a title of a form onLoad?

I'm looking for a way to update a header of an element of a google form with specific data from a cell of google spreadsheet. As the data in the spreadsheet is changing, so should the header of the form element.
Here is my code I'm using.
function readTheSheet() {
var ss = SpreadsheetApp.openById("SpreadsheetKey");
var active = SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.setActiveSheet(ss.getSheets()[4]);
var data = ss.getDataRange().getValues(); // Data for pre-fill
var formUrl = ss.getFormUrl();
var form = FormApp.openByUrl(formUrl);
var items = form.getItems();
var formItem = items[0].asTextItem();
formItem.setTitle('Aktueller Clankrieg: ' + data[1][0]);
Logger.log(data[1][0]);
};
This code is running fine, exept that it's not updating when someone is responding to the form. As per Google Dev the onOpen() trigger runs only when a user opens a form, not when responding to one.
Does anyone know if and how this could be done?
If yes, any help or direction will be GREATLY appreciated.
Thank you in advance! Smite
OnOpen() only triggers when someone opens a form to edit it. :(
To get around this, I set the sheet up to edit the form whenever the relevant columns/rows were changed using onEdit() (onChange() would work also) triggers for those sections.
That was a problem though if someone updated part of the data and then went to lunch/home for the day/etc and someone else used the form in between. If you have a single column/row that matters or if it doesn't matter if it gets piecemeal updates or if you have users that will follow instructions that should work for you.
I ended up changing it to a manually triggered event. The users kept forgetting to use the menu item though so I stuck a "Big Red Button" jpg on the sheet with the data that mattered and associated the script to that. Seems to have done the trick. Whenever they change the part of the sheet that deals with the form they remember to hit the button and the form updates.
Basically grab your updated data from your sheet and then use a combination of:
//code to get the value to update into the form
var Form = FormApp.openById('form id') //to open the form
//more code to get the list of form items and select the right one if you are updating more than one thing
item.getTitle() == 'Item name that you want to update' //That is literally what you typed in that section on the form
Hollar if you need more specifics on logic/syntax.

how to make dynamic google form by modifying stored form

I'm trying to create a dynamic form based on a stored form.
The code I wrote is not working.
When the users that got the form to fill in, run it,
it should first modify all the texts and replace the word kkkk with a keyword determined according to the last submit.
If that cannot be done, then I would like the form when submitted to be modified for the next time it is opened. Is that possible.
I understand that code in onOpen() and onSubmit() do not have permissions to modify the form. So I made my own modifyForm() function, and added a trigger to From-Form On-Submit. Still not working.
The code DID work when I had the trigger set to From-Form On-Open, but only when I closed the form and re-opened it for editing. - That behavior is documented. So, again, I'm looking for a way that each time the form is run, or each time the form is submitted, it is dynamically modified.
function onModify(){
var form = FormApp.getActiveForm();
var imgURL = "http://whatever.com/someimg.jpg";
var img = UrlFetchApp.fetch(imgURL);
// i first check that there is an image item in the current form and then
var imgItem = form.getItems(FormApp.ItemType.IMAGE)[0];
imgItem.setImage(img);
var keyword = "aaaa"; //getKeyword(); // some text returning function
var items = form.getItems();
for (i=0; i<items.length; i++){
var title = items[i].getTitle();
title = title.replace("kkkk", keyword);
items[i].setTitle(title);
}
return form;
}
Thanks for any help you can give!!
Not possible on google forms alone.
So my solution was to create four stored copies of the form replacing "kkkk" keyword in advance, all going to the same spreadsheet but to different sheets, and on a separate website I decide in python which copy of the form to present to the user by redirecting.
I have to store some sort of identification so that the user does not get two types of the form (but that's a separate issue).