Getting information submitted in form created by HtmlService - google-apps-script

I looked at similar questions concerning this topic but still unable to fully understand how to obtain data entered in a form created by HTML.
Here is what I wanted to do:
Create a form (via HTML)
On form submission, data entered is used them to replace the appropriate placeholder keys
in an existing Google Document Template.
email the new Document with replaced text to the user.
I follow this tutorial and was able to get it work. The problem is the UI (Spreadsheet form) is not what I wanted. I want a form in HTML but unable to pull data correctly from it.
Here is a sample script I created using Spreadsheet Form.
var docTemplate = "1234567890"; // Template ID
var docName = "FinalDocument"; // Name of the document to be created
// When form gets submitted
function onFormSubmit(e) {
// Get information from form and set as variables
var email_address = e.values[1];
var full_name = e.values[2];
// Get document template, copy it and save the new document's id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+full_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyEmailAddress', email_address);
copyBody.replaceText('keyFullName', full_name);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "Final Document";
var body = "Here is the form for " + full_name + "";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
// Delete temporary file
DocsList.getFileById(copyId).setTrashed(true);
}
And here is the new form using HTML I just created.
<html>
<form id="myForm">
<input name="fullName" id="_fullName">
<input name="emailAddress" id="emailAddress">
<input type="button" id="submit" value="submit" onclick = "sendData()">
</form>
<script>
function sendData() {
google.script.run.processForm(document.getElementById("myForm"));
}
</script>
</html>
Could someone help me get started on how to transition from using Spreadsheet form to HTML form? How do I pull data from the HTML form?

You might want to refer to this question which I asked before at Accessing object is Google App Script
So for your case it should be:
// Get information from form and set as variables
var email_address = e.emailAddress;
var full_name = e.fullName;
And as for your HTML code
<html>
<form id="myForm">
<input name="fullName" id="_fullName">
<input name="emailAddress" id="emailAddress">
<input type="button" id="submit" value="submit" onclick = "google.script.run.processForm(this.parentNode)">
</form>
</html>
Please give a try, I did not have time to test the code. So sorry.

Related

Google sheet web app search data from sheet error

I want to search data from google sheet and show it in form by web app.
PAN is unique and 5 digit number. When we enter PAN ,5 digit number to( PAN) input form and click update button then it should search data for PAN in sheet and if match then bring entire row to the web form, otherwise it show unavailable.
When we enter PAN number and click update button , it show wrong data in form.
But when we check it by Logger.log() , it show right data .
I don't know and figure out why it show wrong data in web form when we click update button, Please help me and let me know what is the cause for this issue
function doGet(e)
{
return HtmlService.createHtmlOutputFromFile("page");
}
function searchData(pan)
{
var ss=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
//var nameList=ss.getRange("A1:A").getValues().flat();
//var panList=ss.getRange("B1:B").getValues().flat();
//var aadharList=ss.getRange("c1:c").getValues().flat();
//var emailList=ss.getRange("d1:d").getValues().flat();
//var phnList=ss.getRange("e1:e").getValues().flat();
var data=ss.getRange(1,1,ss.getLastRow(),5).getValues();
var panList=data.map(function(r){return r[1];});
var nameList=data.map(function(r){return r[0];});
var aadharList=data.map(function(r){return r[2];});`enter code here`
var emailList=data.map(function(r){return r[3];});
var phnList=data.map(function(r){return r[4];});
var index=panList.indexOf((pan));
if(index>-1)
{
var name=nameList[index];
var aadhar=aadharList[index];
var email=emailList[index];
var phone=phnList[index];
return [name,pan,aadhar,email,phone]
}
else
{ return "unavailable"}
}
Logger.log(searchData(66666))
//html file..(page.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1> Web App </h1>
<label> Name </label>
<input type="text" id="username">
<label> PAN</label>
<input type="number" id="userpan">
<label> Aadhar </label>
<input type="number" id="useraadhar">
<label> Email </label>
<input type="text" id="useremail">
<label> Telepnoe </label>
<input type="text" id="userphone">
<button id="btn"> Update </button>
<script>
//document.getElementById("userpan").addEventListener("input",search);
document.getElementById("btn").addEventListener("click",search);
function search()
{
var pan=document.getElementById("userpan").value;
if(pan.length==5)
{
google.script.run.withSuccessHandler(test).searchData(pan);
function test(s)
{
document.getElementById("username").value=s[0];
document.getElementById("userpan").value=pan;
document.getElementById("useraadhar").value=s[2];
document.getElementById("useremail").value=s[3];
document.getElementById("userphone").value=s[4];
}
}
}
</script>
</body>
</html>
From But when we check it by Logger.log() , it show right data . and your showing script, I thought that the reason of your issue might be due to that the values of panList are the number while var pan=document.getElementById("userpan").value is the string. In this case, even when the inputted value to the input tag is the number 66666, the value of var pan=document.getElementById("userpan").value is the string. By this, var index=panList.indexOf((pan)); is always -1.
If your script is simply modified, please modify it as follows.
From:
var data=ss.getRange(1,1,ss.getLastRow(),5).getValues();
To:
var data = ss.getRange(1, 1, ss.getLastRow(), 5).getDisplayValues();
By this, when pan of 66666, which is the string, is sent from Javascript to Google Apps Script, data retrieved by getDisplayValues() is the string. By this, var index=panList.indexOf((pan)); can be worked.
Note:
I thought that your Google Apps Script might be able to reduce the process cost as follows.
function searchData(pan) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range = sheet.getRange("B1:B" + sheet.getLastRow()).createTextFinder(pan).matchEntireCell(true).findNext();
if (range) {
return sheet.getRange(range.getRow(), 1, 1, 5).getValues()[0];
}
return "unavailable";
}
Note:
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
getDisplayValues()
createTextFinder(findText)

how to pass username and email from GAS to HTML form

im trying to pass username and email to the html form which is called in doGet.
function doGet(e) {
// e has url parameters which contain username and email
var id = e.parameter;
var name = e.postData.contents.split("&")[0];
// after a bunch of splitting ill have two vars
var name and var email, how do i pass this two vars to the index,
return HtmlService.createHtmlOutputFromFile('index').setSandboxMode(
HtmlService.SandboxMode.IFRAME);
}
this is index
<form id="uploaderForm">
<label for="uploaderForm">Upload plusieur fichiers</label>
<div>
//both inputs will be hidden, and will contain the values of name and email variables that i have in doGet
<input type="text" name="applicantName" id="applicantName"
placeholder="nom">
</div>
<div>
<input type="text" name="applicantEmail" id="applicantEmail"
placeholder="Email">
</div>
<div>
<input type="file" name="filesToUpload" id="filesToUpload" multiple>
<input type="button" value="Submit" onclick="uploadFiles()">
</div>
</form>
to sum up, i have two vars in doGet, var name and var email, i wanna pass them to the html index so i can use them as input values , so that the user doesnt have to manually type them
solution 1:
i havent completely tested this yet but im too excited, i spent two days on this i even had nightmares about it last night, so this is how i passed variables to the html form to use in the input
function doGet(e) {
var id = e.parameter;
var name = e.postData.contents.split("&")[0];
var email = e.postData.contents.split("&")[1];
var template = HtmlService.createTemplateFromFile('index');
template.myVar = name.split("=")[1];
template.email = email.split("=")[1];
return template.evaluate().setSandboxMode(
HtmlService.SandboxMode.IFRAME);
}
function doPost(e) {
return doGet(e);
}
and in the html , you can simply call the variables using or whatever you named it like so
<input type="text" name="applicantEmail" id="applicantEmail"
placeholder=<?= email ?> value=<?= email ?>>
the username and email are recieved from a local webpage form that has a post method, so generally im passing username and email to the GAS from my local web page , and then passing it to the html page of the GAS.
solution 2
if you are calling the google script app using and want to pass parameters or variables to the google app script, you can attach them to the URL in the iframe like so
<iframe src="https://script.google.com/.../exec?name=value1&email=value2...">
and then you can access name and email parameters in the google app script in the doGet function like so
function doGet(e) {
var name = e.parameter.name;
var email = e.parameter.email;
var template = HtmlService.createTemplateFromFile('index');
template.myVar = name;
template.email = email;
return template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);

Google script not retrieving value of HTML textarea prompt

I have a HTML prompt for a spreadsheet with 2 input spaces, one for "usuario" which it a text input and the other one for "mensaje" which is textarea.
My script needs to retrieve both values, intert "mensaje" in a specific cell, and download a PDF with "usuario" in the name.
Everything works perfect when it has 2 input type="text", but i need the second one to allow multiple rows so I had to change it.
Now it seems like the textarea "mensaje" information is not transmiting correctly to the script, it isn't inserted into the cell. Everything else works normally.
It doesn't show any error, it just doesn't retrieve the values, so it doesn't insert it, so the downloaded PDF is blank.
I'm not sure what I would need to change to make textarea work correctly, I don't have a lot of experience programing, mostly mashing together parts I found online to make it do what I want.
IndexTexto.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<form id="textform" style="font-size:16px">
Usuario:<br>
<input type="text" name="usuario" style="width: 300px;">
<br>
<br>
Mensaje:<br>
<textarea id="mensaje" rows="14" cols="95"></textarea>
<br><br><br>
<input type="button" value="Descargar" class="action " style="font-size:16px" style="height: 150px;" style="text-align:center;"
onclick="google.script.run
.withSuccessHandler(google.script.host.close)
.descargarTexto(this.parentNode)" />
</form>
</html>
Relevant parts of DescargarTexto.gs
function promptTexto() {
var html = HtmlService.createHtmlOutputFromFile('IndexTexto').setSandboxMode(HtmlService.SandboxMode.IFRAME).setHeight(400).setWidth(700);
SpreadsheetApp.getUi().showModalDialog(html, 'Ingresar texto');
}
function descargarTexto(form) {
SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutput('5').setHeight(10).setWidth(100), "Creando");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Link de pago');
var sheetId = sheet.getSheetId();
var usuario = form.usuario
var mensaje = form.mensaje
sheet.getRange(15,3).setValue(mensaje)
SpreadsheetApp.flush();
var range = sheet.getRange(15,3)
var values = range.getValues()
Logger.log(mensaje)
Logger.log(values)
var date = Utilities.formatDate(new Date(), "GMT+3", "dd-MM-yy")
var filename = usuario + "_" + date + ".pdf"; // Please set the filename here.
You are trying to access undefined object in form.mensaje. If you try to print the form in your descargarTexto(form) function. It will print something like this: {=DEF, usuario=ABC}. The key name for mensaje is not defined. This can be fixed by adding name="mensaje" attribute to mensaje text area.
Note: You can view logs at Executions tab of your App Script project
Your code should look like this:
<textarea id="mensaje" name="mensaje" rows="14" cols="95"></textarea>
Example:
Output:

HTML form file upload to Google Drive and save URL to google sheet

I'm new to the world of google scripting, and have found some great tutorials on how to either:
i Upload a file to Google Drive with HTML form
ii Append new rows to a google sheet.
Essentially I am trying to to write a basic HTML form that collects a few text fields and file attachment, where the file attachment is uploaded to my google drive and the URL along with the other form text fields are appended a Google Sheet.
Here is the HTML form I am working with (based on a tutorial I found):
<!-- Include the Google CSS package -->
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<!-- You can also include your own CSS styles -->
<style>
form { margin: 40px auto; }
input { display:inline-block; margin: 20px; }
</style>
<script>
// The function will be called after the form is submitted
function uploadFile() {
document.getElementById('uploadFile').value = "Uploading File..";
google.script.run
.withSuccessHandler(fileUploaded)
.uploadFiles(document.getElementById("labnol"));
return false;
}
// This function will be called after the Google Script has executed
function fileUploaded(status) {
document.getElementById('labnol').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<!-- This is the HTML form -->
<form id="labnol">
<!-- Text input fields -->
<input type="text" id="nameField" name="myName" placeholder="Your name..">
<input type="email" id="emailField" name="myEmail" placeholder="Your email..">
<!-- File input filed -->
<input type="file" name="myFile">
<!-- The submit button. It calls the server side function uploadfiles() on click -->
<input type="submit" id="uploadFile" value="Upload File"
onclick="this.value='Uploading..';uploadFile();">
</form>
<!-- Here the results of the form submission will be displayed -->
<div id="output"></div>
And here is the google script (again, based on a useful tutorial on a blog)
/* The script is deployed as a web app and renders the form */
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.NATIVE);
// This is important as file upload fail in IFRAME Sandbox mode.
}
/* This function will process the submitted form */
function uploadFiles(form) {
try {
/* Name of the Drive folder where the files should be saved */
var dropbox = "Test Form Submissions";
var folder, folders = DriveApp.getFoldersByName(dropbox);
/* Find the folder, create if the folder does not exist */
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
/* Get the file uploaded though the form as a blob */
var blob = form.myFile;
var file = folder.createFile(blob);
//Allocate variables for submissions in sheet
var namerecord = form.myName;
var emailrecord = form.myEmail;
/* Set the file description as the name of the uploader */
file.setDescription("Uploaded by " + form.myName);
/* Return the download URL of the file once its on Google Drive */
return "File uploaded successfully " + file.getUrl();
var uploadURL = file.getUrl();
//
} catch (error) {
/* If there's an error, show the error message */
return error.toString();
}
//Open spreadsheet based on URL
var googsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/17fuu1vUuxgCgs1TpSGpWDNxMHX3AEFscmjX156HQ5_U/edit?usp=sharing');
Logger.log(googsheet.getName());
var sheet = googsheet.getSheets()[0];
sheet.appendRow(["James", "jim", "abc"]);
}
My intuition was simply to slip some lines of code in to add the form data to the specified sheet but it's not working and I must be doing something wrong :S
Any advice would be greatly appreciated to an ignorant Business Analyst new to web programming :/
Thanks
i had the same problem, and with this link solved my issue :
this a update from google script example for upload file with google sheets and Macros.
In the line in the HTML defining the submit button, change id="uploadFile" to id="uploadFileButton" (there was possibly a collision between the id of the submit button and the function uploadFile())
and also change the onclick trigger by adding an extra return false:
onclick="this.value='Uploading..';uploadFile();return false;"
Correspondingly, in the code defining the uploadFile() function, change
document.getElementById('uploadFile').value = "Uploading File..";
to
document.getElementById('uploadFileButton').value = "Uploading File..";
a complete thread link: https://code.google.com/p/google-apps-script-issues/issues/detail?id=6177
Regards From Venezuela
NOTE: Sorry for my bad English

HtmlService form submit opens new tab with foo bar URL

I am attempting to build a UI for a spreadsheet using GAS HtmlService. The HTML below is a very simple form with a single text box that pulls a value ("Kristina") from the sheet, successfully. However, when I try to submit the form a new tab is opened in Chrome that attempts to open the URL "bffc95ee-ff64-4d2c-xxxx-19d9824eb4b4.foo.bar/?fname=Kristina" with "xxxx" replacing more random letters and numbers (just in case). At no point do I use the words "foo.bar" in my code, so I'm pretty sure that that part isn't coming from me. It does not change each time or after logging out and back in. I'm getting the same result on two different computers.
<html>
<body>
<div>
<form id="formtest1">
<label>First Name</label>
<input name="fname" type="text" maxlength="255" value="<?= fname ?>"/>
<input type="submit" value="Submit"
onclick="google.script.run.processForm(document.getElementById('formtest1'));
google.script.host.close()"/>
</form>
</div>
</body>
</html>
The above is being displayed using the following function:
function htmltest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var html = HtmlService.createTemplateFromFile("HTML");
html.fname = sht.getRange(2, 3).getValue();
ss.show(html.evaluate());
};
If I understand correctly, the "google.script.run.processForm(...)" script in the HTML should trigger the following function, as set up in the projects triggers:
function onFormSubmit(){
Browser.msgBox("Test");
};
But it doesn't appear to do so as the form doesn't close and the msgBox doesn't appear. Only the foo bar URL in a new tab.
Hopefully I've explained the issue clearly and am not making an embarrassing mistake.
You cannot use a real "submit" button with google.script.run (this is a documented restriction in the user guide). Change it to "button" and it should work fine.
The project trigger onFormSubmit() will be triggered by a submission via the Forms Service. There is no relationship between this trigger and your HTML code; they are two different ways to interact with users.
An html forms pattern is shown in the HTML Service documentation here, and the script below is an adaptation of it.
Code.gs
The only real change from your original is that onFormSubmit() has been replaced with processForm(form), which includes a parameter, for the object that will be passed from the html code.
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "htmltest",
functionName : "htmltest"
}];
sheet.addMenu("Custom Menu", entries);
};
function htmltest(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sht = ss.getActiveSheet();
var html = HtmlService.createTemplateFromFile("HTML");
html.fname = sht.getRange(2, 3).getValue();
//Logger.log( html.getCodeWithComments() );
ss.show(html.evaluate());
};
function processForm(form){
var fname = form.fname;
Browser.msgBox("Test - " + fname);
};
HTML.html
This is a modification of your original, echoing the pattern from the documentation. The form submission SuccessHandler is a one-liner, which closes the dialog. Once it completes, the server-side function is invoked with the form content, retrieved using this.parentNode (to refer to the form).
There are other ways - see Get value of html text box in Apps Script function for a different approach.
<html>
<script type="text/javascript">
// SuccessHandler to close form
function close() {google.script.host.close();}
</script>
<body>
<div>
<form>
<label>First Name</label>
<input name="fname" type="text" maxlength="255" value="<?= fname ?>"/>
<input type="button" value="Submit" onclick="google.script.run
.withSuccessHandler(close)
.processForm(this.parentNode)"/>
</form>
</div>
</body>
</html>
Just add this to your script tag on your html file.
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
Source: HTML Service: Communicate with Server Functions