In google sheets I created a menu to add a new employee. It opens a modalDialog using html file (NewEmployee.html) that has a form inside collecting name, starting date, radio buttons (2) and salary (per hour).
HTML Code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function closeForm(){
google.script.host.close();};
function submitForm(){
google.script.run.getInfoFromSubmitForm(document.getElementById("employeeForm"));};
</script>
</head>
<style type="text/css">
.submit-button{
float: right;}
.cancel-button{
float: left;}
</style>
<body>
<div id="myForm">
<form id="employeeForm" class="form">
<label for="employeeName">Employee Name </label>
<input
type="text"
id="employeeName"
name="employeeName"
employeeName="employeeName"
placeholder="This will also be the name of the Sheet"
style="width: 230px;"><br><br>
<label for="date">Please select start Date </label>
<input type="date" id="date" name="date"><br><br>
<label for="employeeType">Please Select Employee Type</label><br>
<input type="radio" id="W2" name="employeeType" value="W2">
<label for="W2">W2</label><br>
<input type="radio" id="W9" name="employeeType" value="W9">
<label for="W9">W9</label><br><br>
<label for="salary">Please enter the Salary(per hour) </label>
<input type="text" id="salary" name="salary" aria-required="true"><br><br>
<input type="button" class="cancel-button" value="Cancel" onclick="closeForm()">
<input type="button" class="submit-button" value="Submit Form" onclick="submitForm();">
</form>
</div>
</body>
</html>
Menu Code:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Driver Menu')
.addItem('Add Employee', 'showNewEmployeeDialog')
.addToUi();`
};
function handling submission:
function showNewEmployeeDialog() {
var widget = HtmlService.createHtmlOutputFromFile("DatePicker.html");
SpreadsheetApp.getUi().showModalDialog(widget, "Enter Employee Information");
}
const getInfoFromSubmitForm = (form) => {
return form;
}
When I click on menu selection, it opens the modalDialog with all fields visible, but script finishes running. I struggle to collect the info and pass it to the function that would store it as object, and that object would be accessible by other functions in the app script (probably global object declaration, but I need it to be cleared, before it updated, so the new employee info overrides it.)
I think, I'm missing proper onSubmit function and/or eventListener.
Goal is to continue running the script until the form is submitted, make sure all inputs are filled and at least one radio button is clicked. Then send the object {name: value, date: value, employeeType: value (based on which radio button is clicked), and salary value. Once the form is submitted, the dialog closes and global object or function should return the object when function is called.
Related
I see a number of questions about "require at least one checkbox to be selected", but none for web apps developed in Google Apps Script.
In a Google Apps Script web app, I can easily require a radio button to be checked with:
<form id="requestNewKeys" onsubmit="handleFormSubmit(this)">
<p>
<label for="primaryToolRadioGroup">What is your primary purpose for requesting Tool XXXXXX</label>
</p>
<div role="radiogroup" id="primaryPurposeRadioGroup">
<input type="radio" id="primaryPurpose0" name="primaryPurpose" value="Research" required="">
<label for="primaryPurpose0">Research</label><br>
<input type="radio" id="primaryPurpose1" name="primaryPurpose" value="Teaching" required="">
<label for="primaryPurpose1">Teaching</label><br>
</div>
<input type="submit" value="Request License">
</form>
And the handleFormSubmit function:
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateResults).processForm(formObject);
}
But I can't figure out the equivalent to require one or more input type="checkbox"s to be checked. I know that Google Apps Script is highly similar to Javascript, but it seems that it's just enough different in this case to make the other solutions I'm finding here not work.
You can try this approach where it only proceeds to the apps script processing if the number of checkboxes ticked is at least 1.
<!DOCTYPE html>
<html>
<body>
<form id="requestNewKeys">
<p>
<label for="primaryToolCheckboxGroup">What is your primary purpose for requesting Tool XXXXXX</label>
</p>
<div role="checkboxgroup" id="primaryPurposeCheckboxGroup">
<input type="checkbox" id="primaryPurpose0" name="primaryPurpose" value="Research">
<label for="primaryPurpose0">Research</label><br>
<input type="checkbox" id="primaryPurpose1" name="primaryPurpose" value="Teaching">
<label for="primaryPurpose1">Teaching</label><br>
</div>
<input type="button" value="Request License" onclick="checkForm()">
</form>
</body>
<script>
function checkForm() {
var checkboxes = document.getElementsByName('primaryPurpose');
var form = document.getElementById('requestNewKeys');
var checked = 0;
checkboxes.forEach(checkbox => {
if(checkbox.checked)
checked++;
});
if(checked > 0)
// google.script.run.withSuccessHandler(updateResults).processForm(form);
else
alert('Please check at least one checkbox!');
}
</script>
</html>
After clicking Request License:
I'm trying to submit the input results of an html form in a container-bound sidebar and copy them to a google sheet. I reviewed a few code examples from this site as well as others (https://www.packtpub.com/mapt/book/web_development/9781785882517/4/ch04lvl1sec48/submitting-form-using-google-script-api-method) but, perhaps because I'm a complete newbie at html/javascript/gas, found them confusing and difficult to follow such that the code I wrote isn't working and I can't figure out why.
In short, I'd like to pass the value entered in 'formcommenttext' input text box to my Google Apps Script function called 'postCommentToSheet', where I'm hoping I can get the value entered by the user and (eventually) write it to a google sheet.
Any suggestions?
Here's my html code:
<!-- input control to add comment -->
<form id="addCommentForm">
<fieldset>
<legend>Add your comment:</legend>
<br>
<input type="text" name="formcommenttext" value=""><br>
<input type="submit" value="Add" onclick="google.script.run.postCommentToSheet(this.parentNode);">
<input type="reset" value="Cancel">
</fieldset>
</form>
I have also include the following code snippet into the script portion of my html form (as suggested elsewhere) though i'm unclear what this does and how to edit it to fit my needs.
function postData(form){
google.script.run
.withSuccessHandler(callback)
.withFailureHandler(callback)
.postFormDataToSheet(form);
}
Here's my .gs code:
function postCommentToSheet(formObject) {
//read formcommenttext from add comment form:
//https://www.packtpub.com/mapt/book/web_development/9781785882517/4/ch04lvl1sec48/submitting-form-using-google-script-api-method
var result = GLOBAL_UI.alert(formObject.formcommenttext.value)
//get comments data sheet
var ss = GLOBAL_DataFile.getSheetByName("Comments");
ss.appendRow([formObject.formcommenttext]);
}
here is how it works :
<form id="addCommentForm">
<fieldset>
<legend>Add your comment:</legend>
<br>
<input type="text" name="formcommenttext" value=""><br>
<input type="submit" value="Add" onclick="google.script.run.postCommentToSheet(this.form);">
<input type="reset" value="Cancel">
</fieldset>
</form>
and the .gs part :
function sidebar(){
var sb = HtmlService
.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showSidebar(sb);
}
function postCommentToSheet(form){
Logger.log(JSON.stringify(form));
var ss = SpreadsheetApp.getActiveSheet();
ss.appendRow([form.formcommenttext]);
}
I added a log to check the content of the form answer and simplified a bit to make it functional in this small example.
You don't currently need the postData() function, but you could call it instead of google.script.run.postCommentToSheet() in case you wanted to do some processing before calling adding the comment to the sheet.
For example, you could run validations to prevent the user from, say, submitting a blank comment. I've included this exact functionality in my example as a demonstration.
Also included is a custom menu so that the sidebar can be opened from within the sheet and the CSS package for add-ons.
Index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<!-- (OPTIONAL) Make your sidebar look consistent with Google Sheets with the below CSS https://developers.google.com/apps-script/add-ons/css -->
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<!-- input control to add comment -->
<form id="addCommentForm" onsubmit=checkData(this)>
<fieldset>
<legend>Add your comment:</legend>
<br>
<input type="text" name="formcommenttext" value="">
<br>
<input type="submit" value="Add">
<input type="reset" value="Cancel">
</fieldset>
</form>
<script>
function checkData(form) {
if (form.formcommenttext.value != "") {
google.script.run.postCommentToSheet(form);
}
}
</script>
</body>
</html>
Code.gs:
// Create a custom menu to open your sidebar
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Open Sidebar", functionName: "openSidebar"});
ss.addMenu("My Custom Menu", menuEntries);
}
// Open the sidebar
function openSidebar() {
var sidebar = HtmlService.createHtmlOutputFromFile("Index");
SpreadsheetApp.getUi().showSidebar(sidebar);
}
function postCommentToSheet(formObject) {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Comments"); // Almost ALWAYS better to explicitly define which sheet to write to
sheet.appendRow([formObject.formcommenttext]);
}
I am trying to make a spreadsheet sidebar that allows a user to input data to create records, as well as edit them. So far I understand how to create the sidebar and display it. I've got a working form that can submit values.
What I am struggling with is how to pre-populate the forms. Form instance some records are associated with others, and I'd like to have a hidden field to store and eventually submit the associated id. Eventually users should also be able to edit records and I'd like to use the same form and just populate the fields and reuse the same submission flow.
I've tried a few different things found on here and other places, but nothing seems to work.
Here is the HTML for the sidebar template
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<style>
</style>
<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);
$('#accountId').val(<? data.accountId ?>);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(alertSuccess).createContact(formObject);
}
function alertSuccess(message) {
var div = document.getElementById('alert');
div.innerHTML = "<p>" + message + "</p>";
google.script.host.close();
}
</script>
</head>
<body>
<p>Enter Contact Info</p>
<form id="contact" onsubmit="handleFormSubmit(this)">
Account Id: <br>
<input type="number" name="accountId" value="0" id="accountId" /><br>
Name:<br>
<input type="text" name="name"/><br>
Phone Number:<br>
<input type="text" name="phone"/><br>
Email:<br>
<input type="email" name="email"/><br>
Contact Type:<br>
<input type="radio" name="type" value="emergency" checked> Emergency<br>
<input type="radio" name="type" value="guardian" checked> Guardian<br>
<input type="radio" name="type" value="other" checked> Other<br>
<input type="submit" value="Submit" />
</form>
<div id="alert"></div>
</body>
</html>
And the accompanying .gs file:
var AlternativeContact = ObjectModel("AlternativeContacts");
function newContact() {
var htmlOutput = HtmlService.createTemplateFromFile("new_contact");
var id = ACCOUNT_MANAGER.getRange("M4").getValue();
htmlOutput.data = {accountId: id};
UI.showSidebar(htmlOutput.evaluate());
}
function createContact(contactJSON) {
var newContact = new AlternativeContact(contactJSON);
newContact.save();
return "Success!";
}
The first line that uses ObjectModel is creating and ORM around the data sheet.
Thanks for the help!
Couple changes and it seems to be working in a basic way.
First, in the scriptlet, i needed to us the printing tag. so use in stead of . This was causing the value to not be used in the rendered template.
Second, I changed my jQuery to:
$(document).ready(function () {
$("input#accountId").val(<?= data.accountId ?>);
});
If anyone is able to answer, I'd be curious why using the $(document).ready is needed. Doesn't everything in the get run? is it an order of operation thing?
I have a form ModalForm on a Google Sheet that inserts rows into the sheet. It's been working fine for months. Starting last week after submitting the form the form disappears and doesn't re-display. I'm not sure why. It executes the insert into the spreadsheet fine. I just never get the form back to insert the next record.
In my Index file, the form code:
<form id="myReceiveForm" name="receive" onsubmit="writeLine()">
Scanner Name : <input id="user" name="user" type="text" required /> <br> <br>
Reference Number: <input id="reference" name="reference" type="text" required /> <br> <br>
Location: <input id="location" name="location" type="text" pattern="[A-Z]{1,3}\-[A-Z]{1,2}\-\d{1,3}\-\d{1,2}" title="Location not in correct format." required/>
<button type="button" value="change" onclick="changeLocation()" >Change Location</button><br> <br>
Product SKU: <input id="sku" name="sku" type="text" value="" autofocus /> <br> <br>
<input type="submit" value="Submit" >
</form>
<script type="text/javascript">
function onSuccess() {
document.getElementById("sku").value = '';
document.getElementById("sku").focus();
return false;
}
function onFailureM(error) {
alert("Invalid Sku");
//alert("SKU" + document.getElementById("sku ").value +" doesn't exist.");
document.getElementById("sku").value = '';
document.getElementById("sku").focus();
}
window.writeLine = function () {
google.script.run
.withSuccessHandler(onSuccess)
.withFailureHandler(onFailureM)
.appendRowstoSheet(document.forms[0]);
}
</script>
In My .gs file:
function openReceiving() {
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showModalDialog(html, '3PL RECEIVING');
Remove onsubmit="writeLine()" from the upper form tag. Change the submit button:
<input type="submit" value="Submit" >
to a regular button with an event:
<input type="button" value="Submit" onmouseup="writeLine()">
This should fix the problem. On Nov. 12th, 2015 Google migrated to IFRAME mode.
All new scripts will default to IFRAME sandbox mode unless NATIVE mode is explicitly specified.
Google Apps Script Sunset Scedule
This is what probably caused your problem. The form submit causes a form tag to disappear. This is expected behavior that has been in place for a long time in regular HTML. But for a long time, HTML Service overrode that behavior. Now, IFRAME mode is more like regular HTML behavior.
In the SKU input field, try adding an onchange attribute if you need the form to submit after the last field is updated:
<input id="sku" name="sku" type="text" value="" autofocus onchange="writeLine()"/>
onchange Event - Reference information
List of all the events
Hi I have created a pop up window containing a form asking the user to enter email and password.And there is a log in button.Usually in most of the forms, after entering all details and pressing 'enter', the submit button will be automatically clicked.But in this case,only when I click the login button it works.I want it to work on pressing 'enter' in keyboard.I know that this is a simple question.But I can't figure it out why is this happening.Please help me
Here is my userinfo.html(pop up window)
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<b>Enter your Email ID and Password</b><br><br>
<form id="userinfo">
<label for="user"> Email : </label>
<input type="text" id="user" /><span id="semail"></span>
<br><br>
<label for="pass">Password : </label>
<input type="password" id="pass" />
<br>
<br>
<input type="button" id="login" value="Log In"/>
</form>
</body>
</html>
Here is my test.js
window.addEventListener('DOMContentLoaded', function() {
var user = document.querySelector('input#user');
var pwd = document.querySelector('input#pass');
var login = document.querySelector('input#login');
login.addEventListener('click', function() {
var userStr = user.value;
var pwdStr = pwd.value;
chrome.runtime.getBackgroundPage(function(bgPage) {
bgPage.login(userStr,pwdStr); });
window.close();
});
});
In order for a submit event to be triggered on ENTER the form must have a submit button.
In your particular case, you need to revent the default behaviour of your form, since you want to handle it "manually" using the background-page.
In summary, the following steps are required:
Change the button type from button to submit.
Register a listener for the form's submit event. (Note: this will be triggered on both button-click and ENTER.)
Prevent the default behaviour on form-submit.
Delegate the login-handling to the background-page (through its login method.
Here is the new code:
test.html
<h4>Enter your Email ID and Password</h4>
<form id="userinfo">
<label for="user">E-mail: </label>
<input type="text" id="user" required />
<br />
<label for="pass">Password: </label>
<input type="password" id="pass" required />
<br />
<br />
<input type="submit" id="login" value="Log In" />
</form>
test.js
window.addEventListener('DOMContentLoaded', function () {
var form = document.querySelector('form#userinfo');
var user = document.querySelector('input#user');
var pass = document.querySelector('input#pass');
/* Register a listener on the form's `submit` event */
form.addEventListener('submit', function (evt) {
/* Prevent the event from being handled by the browser */
evt.preventDefault();
var userStr = user.value;
var passStr = pass.value;
/* Delegate login-handling to background-page */
chrome.runtime.getBackgroundPage(function (bgPage) {
bgPage.login(userStr, passStr);
});
window.close();
});
});
See, also, this short demo.