I am very new to coding and have managed (with some help from friends) to create a form that geo-locates the submitter and writes the values (+coordinate) to a Google Sheet. Where I am having trouble is in the HTML5 REGEX and required validations.
When I click the submit button the REGEX and required validation pop-up windows kick in but unfortunately at the same time, the form data is submitted to the Google Sheet and the data is cleared from the form.
I cannot figure out how to make the validation happen first, and then proceed with the submission instead of both happening simultaneously.
Thank you in advance for your help!
code.gs:
function doGet() {
var html = HtmlService.createTemplateFromFile("test").evaluate()
.setTitle('Engagement Card')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}
function addData(data){
var ss = SpreadsheetApp.openById('1g*********************OnE').getSheetByName('Sheet1');
ss.appendRow(data);
}
test.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
</head>
<body>
<div id="formdiv">
<table width="500">
<tr>
<td align=center>
<img src="https://lh5.googleusercontent.com/5PX_VkGEwpy6YfE9mOBP3tSZ-PE6QW_J2AIIGRYtKuA=w231-h207-p-no" alt="" width='200' />
</td>
<td colspan=2 align=center>
<font size=7>Virtual<br><br>Engagement<br><br>Card *Beta*</font>
</td>
</tr>
</table>
<table width="500">
<tr>
<td colspan=3 align=center>
<font size=3>Please complete the information below</font>
</td>
</tr>
</table>
<form id="form">
<table width="500">
<tr>
<td>First Name:</td>
<td><input type="text" pattern="^[A-Z]+[a-zA-Z]*$" id="first" placeholder="Please type your first name" title="Name must start with a capital letter and not contain punctuation or spaces" required="required" /></td>
</tr>
<tr>
<td colspan=2 align=center><button type="submit" class="action" id="submit">Submit</button></td>
</tr>
</table>
</form>
</div>
<script>
$('#submit').click(function getLocation() {//when the submit button is clicked run this function (getLocation)
if (navigator.geolocation) {//if the browser supports geolocation then...
navigator.geolocation.getCurrentPosition(getData);//get the current position and pass the values to function getData
} else {//if the browser does not support geolocation then...
$('#formdiv').append("Geolocation is not supported by this browser.");//append this message in the web interface
}
});
function getData(position) {//starts the getData function and names data passed to it by getLocation as "position"
console.log(position);//logs the data passed by getLocation in the JS log for viewing
console.log('Running getData');//logs the words "Running getData" in the JS log
var latitude = position.coords.latitude;//assigns the latitude value from geolocation to var latitude
var longitude = position.coords.longitude;//assigns the longitude value from geolocation to var longitude
var coords = [latitude, longitude];//combines latitude and longitude into an array named var coords
var data1 = $('#first').val();//gets the values from the inputs using the input id
var data = [data1,latitude,longitude];//combines data elements in an array named var data
console.log(data);//logs the data values in the JS log for viewing
google.script.run.addData(data);//runs the function in the code.gs file
console.log('Data transmitted');//logs the words "Data transmitted" in the JS log
var field1= document.getElementById('first');
field1.value= field1.defaultValue;
};
</script>
UPDATE 20DEC 1430EST: I changed getLocation to run on submit (vs. on click) using #user9090's advice and added some console logs. Changing to .submit allows the validation and required fields to do their job which is what I was looking for. However, now the script stops in getLocation. "browser supports geolocation" gets logged in the console but then the screen goes white. I believe that getData is not being ran anymore. Any ideas?
$('#form').submit(function getLocation() {//when the submit button is clicked run this function (getLocation)
console.log('getting location');
if (navigator.geolocation) {//if the browser supports geolocation then...
console.log('browser supports geolocation');
navigator.geolocation.getCurrentPosition(getData);//get the current position and pass the values to function getData
} else {//if the browser does not support geolocation then...
console.log('browser does not support geolocation');
$('#formdiv').append("Geolocation is not supported by this browser.");//append this message in the web interface
}
});
function getData(position) {//starts the getData function and names data passed to it by getLocation as "position"
console.log(position);//logs the data passed by getLocation in the JS log for viewing
console.log('Running getData');//logs the words "Running getData" in the JS log
Update 20DEC 1620EST: Turns out, the script works fine now, and validates. My last comment is only true is there is a validation error. If I complete the form abiding by the regex and required elements, the data submits just fine. Although, if I have a validation error, the script hangs in getLocation after the error is corrected and the submit button is pressed again...
Change first 7 lines inside your script block (in test.html) with following lines of code,
$("#form").submit(function(event) {
console.log("Submitting form....");
google.script.run.withSuccessHandler(function(e){
// Do you validation here
}).addData(this); // this is a form's data passed to your GAS function
});
Related
I have a form input field loaded by jquery based on user selection but the HTML form validation and even jquery form validation not working for the input field loaded by jquery.
<tr>
<td colspan="2">
<select name="usdtnetwork" required="required" id="usdtnetwork" onChange="getaddressForm()" title="Please select your USDT Network">
<option>::: Choose your USDT Network :::</option>
<option value="ERC20">ERC20 (ETH)</option>
<option value="TRC20">TRC20 (TRON)</option>
<option value="BEP20">BEP20 (BNB)</option>
</select>
</td>
</tr>
<tr>
<td colspan="2">
<div align="left">
<span id="showinputfield"></span>
</div>
</td>
</tr>
This is my jquery (Noticed I tried e.preventDefault() but can't figure what am doing wrong so I commented it out)
<script>
/*$('.thisbuyUSDT').click(function (e) {
var myForm = jQuery( "#catalog_formusdt" );
// html 5 is doing the form validation for us,
// so no need here (but backend will need to still for security)
if ( ! myForm[0].checkValidity() )
{
// bonk! failed to validate, so return true which lets the
// browser show native validation messages to the user
return true;
}
e.preventDefault(); */
function getaddressForm() {
//e.preventDefault();
$("#loaderIcon").show();
jQuery.ajax({
url: "usdt_form_field.php",
data:'usdtnetwork='+$("#usdtnetwork").val(),
type: "POST",
success:function(data){
$("#showinputfield").html(data);
$("#loaderIcon").hide();
},
error:function (){}
});
}
//}
</script>
you have to reset validation on form after add some element (after $("#showinputfield").html(data);) by :
myForm.removeData("validator").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(myForm );
if it doesn't work please share complete html and jquery code
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
I am trying to replicate a question posed by Pieter Jaspers regarding a conversion of a form from UIApp to HTML. The original question is:
Original question by Pieter Jaspars answered by Sandy Good
If I replicate the code exactly I get the correct result, but when I try to recreate my inline form and amalgamate the two I am not getting a result. The inline form question is here:
HTML inline form formatting question answered by Mogsdad
The code I have so far is in the requisite number of parts, a form and two .gs sheets. I have checked for spelling mistakes and I have tried editing out each line to see what and where I get, but with my limited experience I am drawing a blank. The only minor success is if I run the function InsertInSS() from within the code editor. This posts the word "undefined" in the correct cell in the correct spreadsheet, but not the date as I am trying to do!
Form:
<!-- Use a templated HTML printing scriptlet to import common stylesheet. -->
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<html>
<body>
<div>
<!-- Page header title & 'completion warning -->
<span class="grey"><b>ProReactive Log Form v3.0.74</b></span>
<h4>Complete ALL fields to ensure the form is processed successfully</h4>
<div class="block">
<!-- First input box created -->
<div class="inline form-group">
<label form="date">Date</label>
<input type="date" id="date" style="width: 125px;">
</div>
</div>
</div>
<!-- End of fields for completion, finish form with submission button -->
<button class="share" onclick="runGoogleScript()">submit</button>
</body>
</html>
<script>
function onSuccess(argReturnValue){
alert('was successful ' +argReturnValue);
//ResetFields on Screen
Document.getElementById("date").value = "";
}
function runGoogleScript() {
logger.log('v3.0.74 ran!');
var inputValue = document.getElementById("date").value;
google.script.run.withSuccessHandler(onSuccess)
.InsertInSS(inputValue);
};
</script>
The Code.gs:
function doGet(e) {
return HtmlService.createTemplateFromFile('myForm')
.evaluate()
.setTitle('ProReactiveLog')
.setSandboxMode(HtmlService.SandboxMode.NATIVE);
};
and the seperate.gs:
function InsertInSS(argPassedInName) {
var ssKey = '1cZuEMDrIyzIFm4lGCT20s-Wpv27o0hbbZAsxD1WJFL8';
var SS = SpreadsheetApp.openById(ssKey);
var Sheet = SS.getSheetByName('LOG');
Sheet.getRange(Sheet.getLastRow()+1,1,1).setValue(argPassedInName);
}
Any ideas where I am going wrong? All help as ever, greatly appreciated.
An Apps script HTML App, will not allow a date object to be passed to the server.
google.script.run Parameter Documentation
The documentation states:
Requests fail if you attempt to pass a Date, Function, DOM element besides a form, or other prohibited type, including prohibited types inside objects or arrays.
You will need to pass the date as a string. Convert the date to a string in client side code, and convert it back to a date, if need be, in the server code. However, even if you set the value in the spreadsheet as a string, it may get coerced back into a date without you needing to do anything. Especially if you have that column defined as a date in the spreadsheet.
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
I have a list of items being displayed in a html table, where there is a hyperlink in every row.
When I click the hyperlink, I want to call the servlet with that particular item id.
how can i achieve it?
for 10 items.
<tr>
<td>
<input type="hidden" name="" value="%=request.getAttribute("item_id")%>"
</td>
<td align="center">
<font> (String)providerDetail.get("tripTime")<font />
</td>
<td align="center">
<font>(String) providerDetail.get("noOfSeats")</font>
<td align="center">
<font> Select font </font>
</td>
</tr>
endfor
So, when I click the hyperlink, I need to pass the appropriate item_id to the servlet.
How to have the appropriate input element for the running item_id and to pass the same to servlet?
I am not being able to add html elements as it is not formatted correctly.
On assumption you are using ajax, onclick call a javascript method, pass item_id as parameter to that method.
Then send this to your server as data (I am using jQuery to do this, you can use any other library )
function sendData(item_id){
jQuery.ajax({
type:"POST",
data:"itemId="+item_id,
success: function(data){
//Your code for a successful request goes here.
},
error: function(data){
//Errors treatment goes here.
}
})
}
In case you are doing something like download of a document based on the item id, this is a good example code for that:
var form = '<form action="downloadme"><input type="hidden" name="itemid" value='+item_id+'</form>';
jQuery(form).submit();
Create a form and submit it, and as an hidden parameter pass item_id.
On completion remove that form from body(as you do not need it anymore).
Hope this helps.