How can I process a form using Google Apps Script? - google-apps-script

I am a total noob when it comes to GAS, but I want to pass a form to a local JS function (to validate the data), which then calls a Google function (to add it to a spreadsheet).
Problem is: I can't even get the values out of the form!
My code is like this at the moment:
index.html:
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<div>
<form id="register" action="javascsript:void(0)" onsubmit="validateForm(this)">
Email: <input type="text" name="email" placeholder="someone#example.com" /><br/>
<p id="emailtext"></p><br/>
Smartschool URL: <input type="text" name="url" /><br/>
<p id="urltext"></p><br/>
<input type="submit" value="Submit" />
</form>
</div>
<?!= include('Javascript'); ?>
Javascript.html:
<script>
function validateForm(form) {
// THIS IS NEVER POPPING UP
alert(form.email);
return false;
}
</script>
GoogleCode.gs:
function doGet(e) {
return HtmlService.createTemplateFromFile('Page').evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}

I added a console.log statement to the JavaScript, and looked at the log in my Google Chrome browsers console, and it shows that a form object is getting passed.
I added this line:
console.log('form: ' + form);
To your Javascript file:
<script>
function validateForm(form) {
console.log('form: ' + form);
// THIS IS NEVER POPPING UP
alert(form.email);
return false;
}
</script>
The browser console prints:
form: [domado object HTMLFormElement FORM]
So, the form object is getting passed. You can enumerate all the properties in the Form object to see what is in there, and available to retrieve.
for (var thePropurtees in form) {
console.log('thePropurtees: ' + thePropurtees);
};
You'll get a real long list of everything in the Form object, and you'll notice that email is not in the list. What is in the list is an elements property, that turns out to be another object inside the form object. There is an elements object inside of the form object.
If I enumerate the form elements:
for (var thePropurtees in form.elements) {
console.log('thePropurtees: ' + thePropurtees);
};
I get this:
thePropurtees: 0
thePropurtees: 1
thePropurtees: 2
thePropurtees: item
thePropurtees: email
thePropurtees: url
thePropurtees: namedItem
So, your email data must be in a sub object.
I was able to get the value out of the email input field with this:
console.log('the email value: ' + form.elements.email.value);
There are three levels of objects you need to access, before you can get at the values.
1) Form object
2) Elements object
3) Input object (email)
Your alert would need to be like this:
alert(form.elements.email.value);

Related

Appending access code input into URL as utm tag

I'm currently building a landing page with an access code form field.
I'm stuck on finding a way to get the access code entered into a form to be appended as a tag on the url.
Enter "12345" into field and on submit direct to url "www.website.com/?code=12345"
Below is the code I have so far - :
<script>
function btntest_onclick(){
if (document.getElementById('input-code').value == '1234','5678','9809') {
var domain = "http://www.website.com?";
var data = $(this).serialize();
window.location.href = url
}
else {
alert ( 'not found' );
}
};
</script>
<center>
<span class="text-container">
<input type="text" name="accesscode" placeholder="ACCESS CODE" maxlength="10" size="25" id="input-code">
<p>ENTER</p>
</span>
</center>
Any advice on this would be greatly appreciated!
Thanks.
You have a few problems in the code:
The if containing document.getElementById('input-code').value == '1234','5678','9809'. That's not a valid conditional statement in JS. I assume you were trying to test if the value was equal to any of the strings, which can be done using || (A logical "or").
The code was never added to the end of the URL.
You never defined the url variable you were redirecting to.
Here's a commented version that should explain some ways to do this:
function btntest_onclick() {
// First, we assign the value to a variable, just to keep the code tidy
var value = document.getElementById('input-code').value
// Now we compare that variable against each valid option
// if any of these are true, we will progress
if (value === '1234' || value === '5678' || value === '9809') {
// Use a template literal (The ` quotes) to build the new URL
var url = `http://www.website.com?code=${value}`
// This could also be written as:
// var url = "http://www.website.com?code=" + value
// Navigate to your new URL (Replaced with an alert as a demonstration):
alert(url)
// window.location.href = url
} else {
// Otherwise, show the alert
alert('not found')
}
}
<center>
<span class="text-container">
<input type="text" name="accesscode" placeholder="ACCESS CODE" maxlength="10" size="25" id="input-code">
<p>ENTER</p>
</span>
</center>

Pull data to a html page from Google Sheets based on user input

I have a Google spreadsheet with several rows of data in four columns whose headings are
Employee ID |
Name |
Age |
Designation |
I want to create a web App (html page with form elements) in which if I put in the Employee ID value (which is unique) in a text field and click Submit, the other three details (viz. Name, Age, Designation) of only that particular Employee are displayed in a table below in that same page.
I was not able to see any examples where select parts of the sheet are returned as a table based on user input value.
Would appreciate help.
While I will not be able to code your web app, you can start by researching client-server communication in HTML. The google.script.run API is the most basic call, you can start on that.
You may want to research on scriptlets as well. Basically this allows you to execute Apps Script code in your HTML using the tags <? and ?>.
The templated HTML documentation provides some examples that you can expand to suit your need.
You may also want to study some examples here.
Try something like this:
Note I haven't tested this so some tweaking may be required.
HTML:
<html>
<head>
<base target="_top">
</head>
<body>
<div id="msg"></div><!-- You can add css to hide these and then turn them on with js as required -->
<div id="found"></div>
<form>
<input type="text" name="id" placeholder="Enter Employee ID" /><br />
<input type="button" value="Search" onClick="processForm(this.parentNode);" />
</form>
<script>
function processForm(obj) {
google.script.run
.withSuccessHandler((obj)=>{
if(!obj.msg) {
document.getElementById('found').innerHTML=`EmployeeId: ${obj.id} Name: ${obj.n} Age: ${obj.a} Designation: ${obj.d}`;
}else{
document.getElementById('found').innerHTML=`Message: ${obj.msg}`;
}
})
.search(obj);
}
console.log("My Code");
</script>
</body>
</html>
GS:
function mysearch(obj) {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const [hA, ...data]=sh.getDataRange().getValues();
let idx={};
let found=false;
hA.forEach((h,i)=>{idx[h]=i;});
for(var i=0;i<data.length;i++) {
if(data[i][idx['EmployeeID']]==obj.id) {
Logger.log({id:obj.id,n:data[i][idx['Name']],a:data[i][idx['Age']],d:data[i][idx['Designation']]});
found=true;
break;
}
}
if(found){
return {id:obj.id,n:data[i][idx['Name']],a:data[i][idx['Age']],d:data[i][idx['Designation']]};
} else {
return {msg:"Not found"}
}
}
function launchMyNewDialog() {
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile('ah1'),'test');
}

Creating a dialogue box to capture booking details in Google sheets App Script

I am using Google sheets with app script to build a reservations chart for a hotel
Can someone please tell me if there is a way to add a Dialogue box to a google sheet that can ask multiple questions? I have found the Prompt Dialogue box but that seems to allow only one text box for data entry. I have something like this
var result = ui.prompt(
"Let's get to know each other!",
"Please enter your name:",
ui.ButtonSet.OK_CANCEL
);
// Process the user's response.
var button = result.getSelectedButton();
var text = result.getResponseText();
if (button == ui.Button.OK) {
// User clicked "OK".
ui.alert("Your name is " + text + ".");
} else if (button == ui.Button.CANCEL) {
// User clicked "Cancel".
ui.alert("I didn't get your name.");
} else if (button == ui.Button.CLOSE) {
// User clicked X in the title bar.
ui.alert("You closed the dialog.");
}
If there isnt something pre-built, can you please recommend how else I can capture data which would then feed a second sheet within the same spreadsheet .
many thanks
You need to use the HTML service
The method you are using is quite limited. To go further than that you would need to create your own HTML file and serve it from Apps Script. The flow of that is:
Create an HTML file in the script editor
Create your HTML form
Write a script on the HTML that calls a function on your gs script.
Sample code
Code.gs
// Creates form on UI
function form() {
var htmlOutput = HtmlService
.createHtmlOutputFromFile('form')
.setWidth(250)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Add your info');
}
// Uses info passed from rendered HTML to add data to sheet.
function addForm(data){
console.log(data)
SpreadsheetApp.getActiveSpreadsheet().getRange("A1:C1").setValues([data])
}
form.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// function to run when server-side script is successful
function onSuccess(){
google.script.host.close()
}
// function to run when form is submitted
function sendForm(){
console.log("RUNNING")
let name = document.getElementById("name").value
let country = document.getElementById("country").value
let DOB = document.getElementById("DOB").value
let data = [name, country, DOB]
// call server side function
google.script.run.withSuccessHandler(onSuccess).addForm(data)
}
</script>
</head>
<body>
<form id="form" onsubmit="sendForm()">
<label for="name">First name:</label><br>
<input type="text" name="name" id="name">
<label for="country">Country:</label><br>
<input type="text" name="country" id="country">
<label for="DOB">DOB:</label><br>
<input type="text" name="DOB" id="DOB">
<input type="submit">
</form>
</body>
</html>
Explanation
When the function form() is run from the script editor, it displays your HTML in the Spreadsheet UI.
This shows a form with three text inputs and a submit button.
The submit button has a onsubmit="sendForm()" which is a function defined within the HTML.
It gets all the info from the form, and then calls google.script.run.withSuccessHandler(onSuccess).addForm(data). This is an asynchronous function that sends a request to the gs file to run the addForm function and then when successful, to run the onSuccess function in the HTML.
The onSuccess simply closes the form.
addForm adds the info to a range in the spreadsheet.
Reference
HTML service
Show Modal Dialog
google.script.run

google.script.run.withSuccessHandler does not work properly

I have a HTML code setup within my Google Apps Script project which basically validates the userid and password provided that pair exists in the gSheet or not and according to the verification I either show an alert or redirect to another web-page. When I deploy the code as a web-app, HTML renders just fine, submit button works and executes the gs code however it does not return the value back to the withSuccessHandler function of JS inside the script tag in the HTML code.
I have read a couple of very identical queries in the forum and followed exactly the same path, however I couldn't be able to succeed. For example like this post
It seems there's something that my eyes and mind cannot see - what is it?
Here is the HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div>
<form id="user_login">
<input type="text" name="userid" id="userid" placeholder="enter username"/>
<input type="text" name="pswrd" id="pswrd" placeholder="enter password"/>
<input type="submit" name="login" id="login" value="LOGIN"/>
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
$('#login').click(function() {
console.log("Form submitted...");
google.script.run
.withSuccessHandler(function(response) {
console.log(response);
if (response == true) {
window.open("http://www.google.com", "_self");
} else {
alert("Some alert message here")
}
})
.checkName({
userid: $('#userid').val(),
pswrd: $('#pswrd').val()
});
});
</script>
</body>
</html>
And here is the gs functions
var html;
var verified;
function doGet() {
html = HtmlService.createTemplateFromFile('myformtest').evaluate().setTitle('Web App').setSandboxMode(HtmlService.SandboxMode.NATIVE);
return html
}
function checkName(form){
Logger.log("Form info > "+JSON.stringify(form));
Logger.log("Userid > "+form.userid);
Logger.log("Pwd > "+form.pswrd);
verified = false;
var ss = SpreadsheetApp.openById("1rard7vdpjmfrN81oi2ARhMlLGdNSxC7MqoIw2soj25E").getSheetByName("names");
var values = ss.getDataRange().getValues();
for(n=1;n<values.length;++n){
var username = values[n][0]; // 1 is the index of the column starting from 0
var password = values[n][1];
Logger.log("username: "+username+" | password: "+password);
if (username == form.userid && password == form.pswrd) {
Logger.log("User found in Row("+(n + 1)+")");
verified = true;
break;
}
}
Logger.log("User verified? "+verified);
return verified
}
I can log that the JS is fired correctly with passing the form parameters to the gs function correctly and the gs function executed correctly as well. However, it does not return the true/false value back to the handler function inside the JS.
I expect that when the checkName function is executed, to return the variable's value back to the JS that is to be processed within the withSuccessHandler function and resulting with either redirecting to a definite URL or displaying an alert message.

Google Apps Script with HTML Forms

I am working on a google add-on which uses an HTML sidebar. The sidebar has an HTML form with checkboxes. I want some of the checkboxes to be checked when the user opens the sidebar, based on some User Properties that will already have been initialized. (When the form submits, the Properties are updated. They all start as on). Here is the code for the sidebar:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Settings</title>
<script>
function onSettingsOpen()
{
Logger.log("In the script");
console.log("In the script");
document.getElementById(propsList[0]).checked = (allPreferences.getProperty(propsList[0]) === "true");
document.getElementById(propsList[1]).checked = (allPreferences.getProperty(propsList[1]) === "true");
document.getElementById(propsList[2]).checked = (allPreferences.getProperty(propsList[2]) === "true");
document.getElementById(propsList[3]).checked = (allPreferences.getProperty(propsList[3]) === "true");
document.getElementById(propsList[4]).checked = (allPreferences.getProperty(propsList[4]) === "true");
document.getElementById(propsList[5]).checked = (allPreferences.getProperty(propsList[5]) === "true");
}
</script>
</head>
<body onload="onSettingsOpen()">
<form id="baseSettings" onsubmit="event.preventDefault(); google.script.run.processForm(this)">
<h2>What settings would you like to be on? Please select all that apply.</h2>
<br>
<input type="checkbox" name="checks" value="spaces" id="spaces">Double spaces
<br>
<input type="checkbox" name="checks" value="punctuation" id="punctuation">Punctuation outside of quotes
<br>
<input type="checkbox" name="checks" value="caps" id="caps">Capitilazation at beginning of sentences
<br>
<input type="checkbox" name="checks" value="contractions" id="contractions">Contractions
<br>
<input type="checkbox" name="checks" value="numbers" id="numbers">Small numbers
<br>
<input type="checkbox" name="checks" value="repWords" id="repWords">Repeated words
<br>
<br>
<input type="submit" value="Submit">
</form>
</body>
So as far as I can tell, the Logger.logs and Console.logs aren't running, which implies that the function just isn't running. However, I could not find documentation on running Console/Logger Log functions in an HTML script file; I'm not sure if that is actually the telling factor. What I can't figure out is where to run the function so that it can actually effect the checkboxes. I fear that running it onload of the body won't actually do anything to the checkboxes- it would have to run within the form itself. Where should I call the function?
Here is my create settings pane function:
function openSettings ()
{
populateData ();
initializePreferences();
Logger.log("Data is initialized; pref 1 = " +
allPreferences.getProperty(propsList[0]));
var htmlOutput = HtmlService
.createHtmlOutputFromFile('Settings.html')
.setWidth(300)
.setTitle("Settings");
DocumentApp.getUi().showSidebar(htmlOutput);
}
Any help appreciated!
You could use a function like this when you load the sidebar
<script>
window.onload=function(){
google.script.run
.withSuccessHandler(function(data){
//initialize your checkboxes here
})
.getPropertData();//go to server side to get access to PropertiesService data
};
Client to Server Communication
Your onSettingsOpen references propsList, but this is undefined. You should pass the data in the function by giving the function an argument, e.g. onSettingsOpen(preferences).
Assuming you are storing these preferences in some PropertiesService, when you call Properties.getProperties() you get back an object with key, value pairs. If you make these match your HTML input "id" attributes, you can just lookup the values in the object by passing the id as a key.
Inside the sidebar:
<script>
google.script.run.withSuccessHandler(onSettingsOpen).getAllPreferences();
// #param {Object} preferences - key, value pairs from Properties.getProperties()
function onSettingsOpen(preferences)
{
console.log("In the script");
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (let i = 0; i < checkboxes.length; ++i) {
checkboxes[i].checked = preferences[checkboxes[i].id];
}
}
</script>
Server-side code would need the appropriate getAllPreferences function:
function getAllPreferences() {
return PropertiesService.getUserProperties().getProperties();
}