How to make a form using Google Sheets script editor - google-apps-script

I need to create a Google sheet with 3 columns (column A: Name, column B: Gender and column C: E-mail)
Then I need to add a script to the sheet to make a form (For some reasons I can not use google forms) with the three related questions we just added in the sheet
I can do the form.html code but I am not so much familiar with JavaScript to connect the form to the sheet once submitted
I think it is something like this:
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('form.html');
}
function update spreadsheet {
var sheet = "get active spreadsheet"
...
I am not able to complete the above code, can anybody can help me with this?

You can deploy Apps Script as a Web App [1]. You'll need to create a html file [2] in which you'll put the form you want. Here [3] is well explain how to execute Apps Script functions with JavaScript in the html. Finally, in an Apps Script function you can use the SpreadsheetApp class to insert the values you want [4].
This would be an example code found on the documentation:
Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// 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);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>
code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
[1] https://developers.google.com/apps-script/guides/web
[2] https://developers.google.com/apps-script/guides/html/
[3] https://developers.google.com/apps-script/guides/html/communication
[4] https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app

Related

How do I get the value from a html element

Hi im trying the get the value from a HTML element ID called "SBNum" and use it as a variable called SBNumber on a google script that then retrieves some data with an API.
Here's what I've got so far and I just can't get the value as a variable not sure what I'm missing.
GS CODE
function doGet(request) {
return HtmlService.createTemplateFromFile('Index').evaluate();
}
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
/* #Process Form */
function processForm(formObject) {
var SBNumber = document.getElementById("SBNum").value;
///////////////////START API///////////////////////////
var USERNAME = 'API PASSCODE';
var PASSWORD = 'x';
var url = 'https://URL/api/2.0/documents.json?documentNumber='+SBNumber+'&compact=false&contextId=5';
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ':' + PASSWORD)
};
HTML CODE
<div class="form-row">
<div class="form-group col-md-4">
<label for="SBNum">SalesBinder Number</label>
<input type="text" class="form-control" id="SBNum" >
</div>
</div>
JS CODE
<script>
// 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);
function handleFormSubmit(formObject) {
google.script.run.processForm(formObject);
document.getElementById("myForm").reset();
}
Any help would be greatly appreciated
Thanks
Modification points:
There is no document.getElementById("SBNum") in Google Apps Script.
In your Javascript, handleFormSubmit is not called.
Unfortunately, I cannot know your whole script. So, I would like to propose a modified script by complementing the script.
Modified script:
HTML side:
<form id="myForm">
<div class="form-row">
<div class="form-group col-md-4">
<label for="SBNum">SalesBinder Number</label>
<input type="text" class="form-control" id="SBNum" name="SBNum">
</div>
</div>
<input type="submit" value="submit">
</form>
<script>
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
var value = document.getElementById("myForm");
handleFormSubmit(value);
});
}
// or, I think that you can also use the following script instead of above script.
// document.getElementById("myForm").addEventListener('submit', function(event) {
// event.preventDefault();
// var value = document.getElementById("myForm");
// handleFormSubmit(value);
// });
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(_ => document.getElementById("myForm").reset()).processForm(formObject);
}
</script>
Google Apps Script side:
In this modification, processForm is modified.
function processForm(formObject) {
var SBNumber = formObject.SBNum.value; // Retrieve values from HTML form.
var USERNAME = 'API PASSCODE';
var PASSWORD = 'x';
var url = 'https://URL/api/2.0/documents.json?documentNumber=' + SBNumber + '&compact=false&contextId=5';
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ':' + PASSWORD)
};
// do something
}
When this modified HTML is opened and a value is put to the input tag and a submit button is clicked, the value of inputted value is sent to Google Apps Script. And, the value can be retrieved as var SBNumber = formObject.SBNum.value.
Note:
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script (Author: me)

Create a searching form with 2 input from google sheet database and show result below the form

I am a student who learn to code Apps Script. I want to create a form with 2 number input, let say A & B, with a button. When user submit the form, the script will search column A & B in active Google Spreadsheet sheet that match with 2 input and query a result in the column C on the same row. Finally, the result C will appear below the form.
The problem is that, when the form appear, I input 2 values but the result don't work.
I wrote two file code like this in Apps Script:
The HTML file
<form onsubmit="handleFormSubmit(event)">
<label for="inputA">height:</label><br>
<input type="number" id="inputA" name="inputA"><br>
<label for="inputB">weight:</label><br>
<input type="number" id="inputB" name="inputB"><br>
<input type="submit" value="Submit">
</form><br>
<script>
function handleFormSubmit(event) {
// Prevent the form from refreshing the page
event.preventDefault();
// Get the input values from the form
var inputA = document.getElementById("inputA").value;
var inputB = document.getElementById("inputB").value;
// Search the Google Sheet for a matching row
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var result = "";
for (var i = 0; i < data.length; i++) {
if (data[i][0] == inputA && data[i][1] == inputB) {
result = data[i][2];
break;
}
}
// Display the result on the page
var resultContainer = document.getElementById("result");
resultContainer.innerHTML = result;
}
</script>
<label for="resultA">result is:</label><div id="result"></div>
<!-- Result will be added here -->
The script file:
function doGet(e) {
return HtmlService.createTemplateFromFile('searchForm.html')
.evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
The sheet link is here: https://docs.google.com/spreadsheets/d/1DqjBbU4b0uDTtjYsBFVFDuvA9fthR1N3KUCtkvwRowc/edit?usp=sharing
I think the problem is the code in script tag but I don't quite sure.
Modification points:
In your script, it seems that you are using Google Apps Script in the Javascript on the HTML side. Google Apps Script can be used on the server side. So, in this case, google.script.run is used.
When these points are reflected in your script, how about the following modification?
Modified script: searchForm.html
HTML & Javascript:
<form>
<label for="inputA">Input A:</label><br>
<input type="number" id="inputA" name="inputA"><br>
<label for="inputB">Input B:</label><br>
<input type="number" id="inputB" name="inputB"><br>
<input type="submit" value="Submit" onclick="handleFormSubmit(event)">
</form>
<div id="result">
</div>
<script>
function handleFormSubmit(event) {
event.preventDefault();
var inputA = document.getElementById("inputA").value;
var inputB = document.getElementById("inputB").value;
google.script.run.withSuccessHandler(result => {
var resultContainer = document.getElementById("result");
resultContainer.innerHTML = result;
}).sample(inputA, inputB);
}
</script>
Google Apps Script: code.gs
function doGet(e) {
return HtmlService.createTemplateFromFile('searchForm.html').evaluate();
}
function sample(inputA, inputB) {
var sheet = SpreadsheetApp.getActiveSheet(); // or var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var data = sheet.getDataRange().getValues();
var result = "";
for (var i = 0; i < data.length; i++) {
if (data[i][0] == inputA && data[i][1] == inputB) {
result = data[i][2];
break;
}
}
return result;
}
Note:
As an important point of this modification, google.script.run is run with the asynchronous process. Please be careful about this.
When you modified the Google Apps Script of Web Apps, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in my report "Redeploying Web Apps without Changing URL of Web Apps for new IDE (Author: me)".
Thit is a sample modification. So, please modify this for your actual situation. If you want to know about google.script.run more, you can also see various sample scripts at Stackoverflow.
Reference:
Class google.script.run (Client-side API)

Populate Google Form using Google App Script on Form open

I have a google form to where I want to populate with some data from a spreadsheet when user is opening the form.
I have a ListItem which I populate it with spreadsheet data. Until now I used the Open(e) function and a trigger, but I just found out that this method is triggered only on form edit not on form open.
Do you have an idea how can I do that?
To have an idea on what I want, I have two files, Code.gs contains the main functions like onOpen and onFormSubmit, and ItemClass where I get my data and create the UI.
I set a console log to Open(e) function, but never triggers.
Code.gs
function onOpen(e) {
console.log({message: 'onOpen', initialData: e});
let items = getItems();
let form = FormApp.openById(PARAMS.formID);
form.setTitle('New Form')
createUI(form, items);
}
ItemsClass.gs
function getItems() {
var email = Session.getActiveUser().getEmail();
var allItems = SpreadsheetApp.openByUrl(PARAMS.sheetURL).getSheetByName("Items Stream").getDataRange().getDisplayValues();
var headers = allItems.shift();
var items = new Array;
for (var i = 0; i < allItems.length; i++) {
var first = allItems[i][1]
var second = allItems[i][2]
items.push(first + "&" + second)
}
return items;
}
The on Open trigger Google Forms works only when opening the form editor, not the actual form that the user fills out
To return to the user the updated data whenever he opens the form and allow him to modify the data, you should create a custom HTML form with Web polling.
Web Polling with setInterval allows to pull fresh data from the spreadsheet and update it in specified intervals
Apps Script WebApps allow you to combine Apps Script and HTML/Javascript which allows you easy interaction between serverside and UI - useful for creation of a custom HTML form
Use google.script.run to communicate between the two sides.
Simple sample pulling updated data from column A in a spreadsheet and allowing the user to modify the values:
code.gs:
var sheet = SpreadsheetApp.openById('XXX').getSheetByName("YYY");
function doGet(){
var html=HtmlService.createTemplateFromFile('index');
return html.evaluate();
}
function getValues() {
//get data from the first column
var data = sheet.getRange(1, 1, sheet.getLastRow(), 1).getValues();
var table = "";
for (var i = 0; i < data.length; i++) {
table +='<tr><td>' + data[i][0] + ' </td><tr>';
}
return table;
}
function writeToSheet(newValues) {
newValues = newValues.split(",");
var range = sheet.getRange(1, 1, newValues.length, 1);
newValues = newValues.map(function(row){return [row]});
range.setValues(newValues);
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<script>
function onSuccess(values){
document.getElementById("data").innerHTML=values;
}
function polling(){
//modify the interval of 2000 ms to any desired value
setInterval( function(){google.script.run.withSuccessHandler(onSuccess).getValues()},2000);
}
function updateValues(){
var newValues= document.getElementById("newValues").value;
google.script.run.writeToSheet(newValues);
}
</script>
<body onload="polling()">
<div> Values: </div>
<table id="data">
</table>
<div> If you want to modify the values in the spreadsheet, type in new values comma separated: </div>
<input type="text" id="newValues" ><br><br>
<input type="button" value="Confirm" onclick="updateValues()">
</body>
</html>
Deploy this WebApp and described in the documentation and paste the WebApp URL into a browser address bar.

the eSignature dilemma

I have a form that needs an eSignature collected via mobile. I need it to be free with unlimited responses. I have a working jSignature HTML code for Google Sheets, but I cannot get it to work on mobile.
Ideally, I'd like to stick with Google, though I've been experimenting outside of it with things like Wix (doesn't do exactly what I need it to) or Android Studio (beyond my ability). My ability beyond that isn't great by any means so I'm not sure where to begin, though I have a suspicion it isn't about what I can do so much as what google sheets can do, as in, I've read a bit about how scripting doesn't work well on mobile.
HTML
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/></head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/willowsystems/jSignature/master/libs/jSignature.min.js"></script>
<body>
<form id="customerForm">
Please sign your name in the pad below: <br>
Full Name: <input type="text" name="username"><br>
Employee Number: <input type="employeenumber" name="useremployeenumber"><br><br>
Signature:
<div id="signature"></div><br>
<img id="rendered" src="" style="display:none">
<input type="button" value="Save" onclick="renderSignature();saveImage();"/>
</form>
</body>
<script>
document.getElementById("signature").style.border = "1px solid black";
$("#signature").jSignature({
'background-color': 'transparent',
'decor-color': 'transparent'
});
function renderSignature(){
$("img#rendered").attr("src",$('#signature').jSignature('getData','default'));
}
function saveImage(e){ //This sends the image src to saveImages function
var bytes = document.getElementById('rendered').src;
console.log(bytes);
var sign = {
username: document.getElementsByName('username')[0].value,
useremployeenumber: document.getElementsByName('useremployeenumber')[0].value
};
google.script.run.saveImage(bytes, sign);
return
}
window.onload=function(){
google.script.run
.withSuccessHandler(function(){google.script.host.close();})
.saveImage(bytes, sign);
}
</script>
</html>
CODE.GS
function showDialog() {
var html = HtmlService.createHtmlOutputFromFile('jSignature')
.setWidth(400)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Your Signature is Required');
}
function doGet() {
return HtmlService
.createTemplateFromFile('jSignature')
.evaluate();
}
function saveImage(bytes, sign){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('my page name');
var dateObj = Date.now();
var bytes = bytes.split(",")
var blob = Utilities.newBlob(Utilities.base64Decode(bytes[1]), 'image/png');
var fileName = blob.setName("Signature "+dateObj).getName();
var sigFolder = DriveApp.getFolderById("my folder id");
var url = sigFolder.createFile(blob).getId();
Logger.log(url)
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Register');
var name = sign.username;
var employeenumber = sign.useremployeenumber;
var signature = ss.insertImage(blob,4,ss.getLastRow()+1);
signature.setWidth(500);
signature.setHeight(20);
signature
var imageCell = ss.getRange(ss.getLastRow()+1, 1, 1, 3).setValues([[Date(), name,employeenumber]]);
}
What I've been thinking about is having the user open the form responses google sheet first, to a page with a link to the form. They would follow that link, fill out the form then be taken back to the google sheets form where an onFormSubmit trigger would bring up the jSignature pad. They would sign and all the information would be collected on one line in the form responses.
How do I make jSignature work for Google Sheets mobile? Is it even possible?

Uploading file to spreadsheet requires special permissions

I'm writing a script for Google Sheets which opens a form for uploading a file, and calls server-side function to handle the uploaded file. The problem I have is that the server-side function does not get called and failure handler is invoked with error message saying that I have no permissions to do the operation.
If I call the server side function with null argument instead of passing in the form then the function successfully gets called.
Here is the script I have:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "Process bank statement file", functionName: "openUploadPaymentsDialog"}];
ss.addMenu("AG_Menu", csvMenuEntries);
}
function openUploadPaymentsDialog(e) {
var html = HtmlService.createHtmlOutputFromFile('UploadPaymentsDialog');
SpreadsheetApp.getUi().showModalDialog(html, 'Upload .NDA file');
Logger.log('dialog opened');
}
function handleFileUpload(theForm) {
Logger.log('file uploaded');
}
And HTML form:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form>
<input type="file" name="theFile"/><br/><br/>
<input type="button" value="Submit" onclick="onSubmit(this.parentNode);"/>
</form>
<div id="output"/>
<script>
function onSubmit(theForm) {
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(onFailure)
.handleFileUpload(theForm);
//if I call handleFileUpload with null as argument then call succeeds
}
function onFailure(error){
var div = document.getElementById('output');
div.innerHTML = "ERROR: " + error.message;
}
function onSuccess(f){
google.script.host.close();
}
</script>
</body>
</html>
The script is bound to the spreadsheet and I'm not the owner of the spreadsheet, but I have permissions to edit. I'm running the script from my user (not owner).
Is it so that only owner can upload files? Why is that?
I found out that it is probably some problem with browser I'm using. It is Google Chromium under Debian Linux. I have just tried it with Firefox and it works OK.