I'm working through https://developers.google.com/apps-script/guides/html/communication trying to submit a form with info loaded from a google sheet. On the client side I have (Based heavily on the form example in the article) :
<!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)">
<div>
<select id="optionList" name="email">
<option>Loading...</option>
</select>
</div>
<br>
<div>
<textarea name="message" rows="10" cols="30">
The cat was playing in the garden.
</textarea>
</div>
<input type="submit" value="Submit" />
</form>
On the server side (code.gs) I have:
function processForm(formObject) {
Logger.log('in here');
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}
I can see that the submit is working because I see 'in here' in the logs. How can I access the form fields from within the processForm function?
This chunk doesn't make sense to me
var formBlob = formObject.myFile;
Your form doesn't contain the input whose 'name' attribute is set to 'myFile'. Once you click 'submit', the 'formObject' variable will be:
{
email: "Loading...", //from <select id="optionList" name="email">
message: "The cat was playing in the garden." //from <textarea name="message">
}
Related
I'm busy with an Apps Script Web App and would like to populate input boxes within the web app with data from a google sheet.
I'm trying to retrieve data when a button is clicked and populate fields within the webapp with the data that is retrieved from the sheet. I just can't seem to get the text box fields to be updated after retrieving the data from google sheets.
Any help would be greatly appreciated.
The code I have so far is:
Code.gs file
function doGet() {
var htmlOutput = HtmlService.createTemplateFromFile("page");
return htmlOutput.evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
var idx;
var nextLead;
var totalLeads;
var remainingLeads;
function assignLead() {
var ss = SpreadsheetApp.openById("sheetId");
var ws = ss.getSheetByName("leads");
var range = ws.getRange(1, 1, ws.getLastRow(), ws.getLastColumn())
var data = range.getValues();
//console.log(data);
var status = data.map(function (row) {
return row[11];
});
//console.log(status);
idx = status.indexOf("unassigned");
//console.log(idx)
for (var i = 0; i < data.length; i++) {
nextLead = data[idx];
updateStatusAssigned(idx)
}
// console.log(nextLead);
// console.log(data);
}
function updateStatusAssigned(row) {
var ss = SpreadsheetApp.openById("SheetId");
var ws = ss.getSheetByName("leads");
var range = ws.getRange(1, 1, ws.getLastRow(), ws.getLastColumn())
ws.getRange(idx + 1, 12).setValue("assigned")
}
page html file
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<?!= include("page-css") ?>
</head>
<body>
<div>
<!-- Header -->
<div class="header">
<h1>Header</h1>
</div>
<!-- Agent Info -->
<div class="row">
<div>
<p><label for="agnet">Agent Name:</label><input id="agent" type="text" ></input>
<label for="loginTime">Login Time:</label><input id="loginTime" type="text"></input></p>
<p><label for="campaign">Current Campaign:</label><input type="text" id="campaign"></input></p>
<button id="btn-getLead" style= float: right>Get Lead</button>
</div>
<!-- <div>
<button id="btn" style=”float: right”>Get Lead</button>
</div> -->
</div>
<!-- Lead Details Banner -->
<div class="row">
<div class="container">
<h3>Lead Details</h3>
</div>
<!-- Customer Information -->
<div class="flex-container">
<div>
<p>
<h5>Customer Information</h5>
</P>
<label>Name:</label><input type="text" id="name"></input>
<label>Surname:</label><input type="text" id="surname"></input>
<label>ID Number:</label><input type="text" id="id"></input>
<p><label>Address:</label><input type="text" id="add"></input><label>Postal Code:</label><input type="text" id="code"></input></p>
<p><label>Suburb:</label><input type="text" id="sub"></input></P>
<p><label>Postal Address:</label><input type="text" id="p-add"></input></p>
<p><label>Tel Number:</label><input type="tel" id="tel"></input>
<label>Mobile Number:</label><input type="tel" id="cell"></input>
<label>Alternate Number:</label><input type="tel" id="alt"></input></p>
<p>
<label>Disposition</label>
<select id="dispo">
<option> </option>
<option>Wrong Number</option>
<option>No Answer</option>
<option>Win</option>
</select>
</p>
<p>
<button id="submit">Submit</button>
</p>
</div>
<!-- Call Notes -->
<div>
<p>
<h5>Call Notes</h5>
</p>
<textarea rows="15" cols="50" id="notes"></textarea>
</div>
</div>
<?!= include("page-js") ?>
</body>
</html>
page-js file
<script>
document.getElementById("btn-getLead").addEventListener("click",getLeadData);
function getLeadData(){
google.script.run.assignLead()
document.getElementById("name") = nextLead[0];
}
</script>
Modification points:
Unfortunately, the variables declared as the global at Google Apps Script side cannot be used for Javascript side. So nextLead of document.getElementById("name") = nextLead[0]; cannot be used.
I thought that this is due to the reason of your issue.
In this case, withSuccessHandler can be used.
And, I think that document.getElementById("name") = nextLead[0]; occurs an error. In this case, please modify to document.getElementById("name").value = nextLead[0];.
When above points are reflected to your script, it becomes as follows.
Modified script:
Google Apps Script side:
Please modify assignLead() as follows.
From:
for (var i = 0; i < data.length; i++) {
nextLead = data[idx];
updateStatusAssigned(idx)
}
// console.log(nextLead);
// console.log(data);
}
To:
for (var i = 0; i < data.length; i++) {
nextLead = data[idx];
updateStatusAssigned(idx)
}
// console.log(nextLead);
// console.log(data);
return nextLead; // Added
}
Javascript side:
From:
function getLeadData(){
google.script.run.assignLead()
document.getElementById("name") = nextLead[0];
}
To:
function getLeadData(){
google.script.run.withSuccessHandler(nextLead => {
document.getElementById("name").value = nextLead[0];
}).assignLead();
}
Note:
In this modified script, it supposes that your function of assignLead() works fine and nextLead is the correct value you want. Please be careful this.
Reference:
withSuccessHandler(function)
I am trying to make mobile app using Phonegap. I am writing a code using HTML to search an ID in google sheet and give the complete row in return. Following is my HTML code.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div class="form-row">
<div class="form-group col-md-2">
<label for="idNum">ID Number</label>
<input type="text" class="form-control" id="idNum">
<output id="rnum"></output>
</div>
<button type="button" class="btn btn-outline-info" id="searchbtn" onclick="search_ID()">Search Profile</button>
</div>
<p id="demo"></p>
<form class="google_script" method="POST"
action="https://script.google.com/macros/s/AKfycbwlHuXwW1fEDfeer1ot6Ltb9cqT83VRZfQQQdTqZSgPvpYapUs/exec">
<script data-cfasync="false" src="index.js"></script>
</body>
</html>
and index.js file is:
function search_ID() {
var input = document.getElementById("idNum").value;
if (isNaN(input)) {
voteable = "Input is not a number";
} else {
voteable = (input.length ==6 ) ? "Correct Value" : "Wrong Value";
}
document.getElementById("demo").innerHTML = voteable;
google.script.run.doSomething();
}
I want to call function in Google Script from local HTML file to get the data from google sheet (Given public view). Please help.
I think you want to do something like this:
function search_ID() {
var input = document.getElementById("idNum").value;
if (isNaN(input)) {
voteable = "Input is not a number";
} else {
voteable = (input.length ==6 ) ? "Correct Value" : "Wrong Value";
}
document.getElementById("demo").innerHTML = voteable;
google.script.run.
.witSuccessHandler(function(obj){
window.alert(obj.msg);
})
doSomething();
}
You can also do it like this:
google.script.run
.withSuccessHandler(functionname)
.doSomething()
function functionname() {
window.alert('obj.msg');
}
gs:
function doSomething() {
//
return {msg:"I did something and returned;"}
}
client to server communication
First I will provide you with the code and briefly explain what it is I am trying to accomplish.
Code.gs
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu("Custom Menu")
.addItem("Show sidebar", "showSidebar")
.addToUi();
}
function doGet() {
return HtmlService.createHtmlOutputFromFile("entry");
}
function showSidebar() {
var html = HtmlService.createHtmlOutputFromFile("entry")
.setTitle("My custom sidebar")
.setWidth(300);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showSidebar(html);
}
function EnterData(fobject) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
sheet.activate();
ss.toast("Something Happened");
var range = sheet.getRange(1, 1);
range.setValue("It worked");
}
function ProgramSuccess() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.toast("Program Run Complete");
}
entry.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent form 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 FormSubmit(formObject) {
google.script.run.withSucessHandler(FormSuccess).EnterData(formObject);
}
function FormSuccess() {
google.script.run.ProgramSuccess;
google.script.host.close();
}
</script>
</head>
<body>
<form id="entryForm" onsubmit="FormSubmit(this)">
Name:<br>
<input type="text" name="name">
<br>
Client Name:<br>
<input type="text" name="clientname">
<br><br>
<input type="submit" value="Submit">
<input type="reset">
</form>
</body>
</html>
The purpose of this program is to open a sidebar in a google sheet that displays an html page that has a form (tag). Then when you click submit in the html sidebar, it should run the EnterData function in Code.gs. My problem is that this function is not being ran and nothing happens when I click the submit button.
Any help on this would be greatly appreciated.
Try this:
entry.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent form 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 FormSubmit() {
google.script.run.withSucessHandler(FormSuccess).EnterData(document.getElementById("entryForm"));
}
function FormSuccess() {
google.script.run.ProgramSuccess;
google.script.host.close();
}
</script>
</head>
<body>
<form id="entryForm">
Name:<br>
<input type="text" name="name">
<br>
Client Name:<br>
<input type="text" name="clientname">
<br><br>
<input type="submit" value="Submit" onclick="FormSubmit()">
<input type="reset">
</form>
</body>
</html>
Also, i did not understand why are you passing the "entryForm" object to the EnterData function because you don't seem to be making use of it.
I'm using an AngularJS form for a contact form and would like to reset the form on successful submission. I've found plenty of examples of how to reset an AngularJS Form and have that working, however, I've been unable to figure out a way to successfully reset the form on submission. My reset() function clears the form fields and appears to set the state of the form back to pristine when called on submit, however, the messages that should only be shown when a field is invalid are still displayed.
Here's my controller code with the function...
function ContactCtrl() {
var vm = this;
vm.reset = reset;
vm.submit = submit;
function reset(form) {
if (form) {
vm.name = undefined;
vm.email = undefined;
form.$setValidity();
form.$setPristine();
form.$setUntouched();
}
}
function submit(form) {
if (form) {
vm.reset(form);
}
}
}
The full code can be found below or on Plunker
angular
.module('plunker', [])
.controller('ContactCtrl', ContactCtrl);
function ContactCtrl() {
var vm = this;
vm.reset = reset;
vm.submit = submit;
function reset(form) {
if (form) {
vm.name = undefined;
vm.email = undefined;
form.$setValidity();
form.$setPristine();
form.$setUntouched();
}
}
function submit(form) {
if (form) {
vm.reset(form);
}
}
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.9/angular.js" data-semver="1.4.9"></script>
<script src="app.js"></script>
</head>
<body ng-controller="ContactCtrl as contact">
<form name="form" novalidate>
Name:
<input type="text" ng-model="contact.name" name="uName" required="" />
<br />
<div ng-show="form.$submitted || form.uName.$touched">
<div ng-show="form.uName.$error.required">Tell us your name.</div>
</div>
E-mail:
<input type="email" ng-model="contact.email" name="uEmail" required="" />
<br />
<div ng-show="form.$submitted || form.uEmail.$touched">
<span ng-show="form.uEmail.$error.required">Tell us your email.</span>
<span ng-show="form.uEmail.$error.email">This is not a valid email.</span>
</div>
<input type="button" ng-click="contact.reset(form)" value="Reset" />
<input type="submit" ng-click="contact.submit(form)" value="Submit" />
</form>
<pre>
FORM:
form.$pristine = {{form.$pristine}}
form.$dirty = {{form.$dirty}}
form.$submitted = {{form.$submitted}}
NAME:
form.uName.$pristine = {{form.uName.$pristine}}
form.uName.$dirty = {{form.uName.$dirty}}
form.uName.$valid = {{form.uName.$valid}}
form.uName.$invalid = {{form.uName.$invalid}}
EMAIL:
form.uEmail.$pristine = {{form.uEmail.$pristine}}
form.uEmail.$dirty = {{form.uEmail.$dirty}}
form.uEmail.$valid = {{form.uEmail.$valid}}
form.uEmail.$invalid = {{form.uEmail.$invalid}}
</pre>
</body>
</html>
you could put the function you want to run on-submit inside of an ng-submit directive, this appears to get executed the same as the reset button:
<form name="form" ng-submit="contact.submit(form)">
Try the following, adding ng-submit
<form name="form" novalidate ng-submit="contact.submit(form)">
It worked for me.
Your button should look like this now
<input type="submit" value="Submit" />
hope this helps.
I also found that if you want to still use the form submit instead of ng-submit event, you need to wrap your form clearing code in a $timeout function. This forces the code you stick inside the $timeout to execute 'synchronously' to any other event actions (in this case the form submit).
Modified Plunkr seen here
angular
.module('plunker', [])
.controller('ContactCtrl', ['$scope','$timeout', ContactCtrl]);
function ContactCtrl($scope, $timeout) {
var vm = this;
vm.reset = reset;
vm.submit = submit;
vm.resetMe = resetMe;
function reset($event, form) {
if ($scope.form) {
$timeout(function(){
vm.name = undefined;
vm.email = undefined;
$scope.form.$setValidity();
$scope.form.$setPristine();
$scope.form.$setUntouched();
});
}
}
function submit(form) {
if (form) {
vm.reset(form);
}
}
function resetMe(){
console.log($scope);
debugger;
$scope.form.$setPristine();
}
}
Since the NATIVE sandbox on google apps script is deprecated, I'm switching to IFRAME, which has caused some issues.
The basic outline of the app is that it should allow a user to fill in some information and upload a file (it also makes sure all required fields are completed). Upon submission (by clicking a button), the file should be uploaded to a folder in google drive and a spreadsheet should be updated with the user's information. When I'm in NATIVE, everything works fine. When I set it to IFRAME, nothing happens when I click the submit button.
This is a similar issue to here and here, but neither of them directly address my problem. I also tried following the Google Guide but it didn't help.
Here is my server.gs script:
function doGet(e) {
return template = HtmlService.createHtmlOutputFromFile('form.html').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFiles(form) {
try {
var dropbox = "Applications";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var CV = form.CV;
var foldername = form.myLastName + ", " + form.myFirstName;
var myFolder = folder.createFolder(foldername);
var file_CV = myFolder.createFile(CV);
var CV_url = file_CV.getUrl();
var sheet_return = addApplicant(form, CV_url);
return "Thank you for your submission."
} catch (error) {
return error.toString();
}
}
function addApplicant(form, CV_url) {
try {
var d = new Date()
var ss = SpreadsheetApp.openByUrl(***INSERT URL TO GOOGLE SHEETS PAGE***);
SpreadsheetApp.setActiveSpreadsheet(ss);
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);
var sheet = SpreadsheetApp.getActiveSheet();
if (form.visa != "Yes"){
form.visa = "No"
}
sheet.appendRow([d, form.myFirstName, form.myLastName, form.myEmail, form.visa, CV_url]);
} catch (error) {
return error.toString();
}
}
Here is my form.html script:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<!-- You can also include your own CSS styles -->
<link href='https://fonts.googleapis.com/css?family=Bitter' rel='stylesheet' type='text/css'>
<style type="text/css">
.warning {border: 1px solid red !important; background: #fdecb2 !important;}
.hideClass {display:none;}
</style>
<div class="form-style-10">
<title> Application </title>
<form id="myForm" name="myForm">
<fieldset class="fields">
<div class="section"> Personal Information </div>
<div class="inner-wrap">
<label for="myFirstName"> First Name* </label>
<input type="text" id="myFirstName" name="myFirstName" placeholder="" required />
<label for="myLastName"> Last Name* </label>
<input type="text" name="myLastName" placeholder="" required />
<label for="myEmail"> Email* </label>
<input type="email" name="myEmail" placeholder="" required />
<span class="visa-checkbox">
Check if you will require visa assistance. <input type="checkbox" name="visa" value="Yes" />
</span>
</div>
</fieldset>
<fieldset class="fields">
<div class="section"> Documents (pdf format is preferred) </div>
<div class="inner-wrap">
<label for="CV"> CV* </label>
<input type="file" name="CV" required />
</div>
</fieldset>
<p> </p>
<p id="incompleteWarning" class="hideClass"> Please check for incomplete fields and re-submit. </p>
<p id="bePatient" class="hideClass"> Please be patient while the files are being uploaded. Do not close or refresh the form. </p>
<input id="submitbutton" type="button" value="Submit Application" />
</form>
<div id="output" class="hideClass">
<span id="ThankYou" >Thank you for taking the time to complete the application.
</span>
</div>
</div>
<script type="text/javscript">
document.getElementById('submitbutton').addEventListener("click", validatefunction);
function validatefunction() {
document.getElementById('submitbutton').val = 'Submitting...';
//check for required fields
var j = 0;
var form = document.getElementById('myForm');
var elem = form.elements;
for (var i = 0; i < elem.length; i++){
elem[i].className = "";
if (elem[i].value === "" && elem[i].hasAttribute('required')){
elem[i].className = "warning";
j++;
}
}
if (j === 0) {
var btn = document.getElementById('submitbutton');
btn.disabled = true;
document.getElementById('incompleteWarning').style.display = 'none';
document.getElementById('bePatient').style.display = 'inline';
google.script.run.withSuccessHandler(fileUploaded).uploadFiles(this.parentNode);
} else{
document.getElementById('submitbutton').val = 'Submit Application';
document.getElementById('incompleteWarning').style.display = 'inline';
document.getElementById('incompleteWarning').style.color = 'red';
}
};
</script>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').style.display = 'inline';
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
</body>
</html>
Change:
<script type="text/javscript">
To:
<script language="javascript">
I don't know why it doesn't like type="text/javscript"