Refresh the deployed HTML web page using Google Apps Script - html

I have created a small website using HTML service of Google apps script.
Here is GAS Code
function doGet() {
var t = HtmlService.createTemplateFromFile('form');
t.email=Session.getActiveUser().getEmail();
return t.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
and this is HTML Code
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<base target="_top">
</head>
<body onLoad="addEventListeners()">
<div class="container-fluid">
<form id="form1">
<label for="comp_indiv_name" id="company_individual_name" style="display: block" >2. COMPANY NAME</label>
<input type="text" class="form-control" name="cName" required>
<br>
<input type="submit" class="btn btn-primary" value="Create Contract Now">
</form>
</div>
<script>
function addEventListeners() {
var condition=true;
document.getElementById('form1').addEventListener('submit', function(e){
e.preventDefault();
if(condition==true){condition=false;google.script.run.addData(this);}});
}
</script>
</body>
</html>
HTML page has one form with just one question, and when that form is submitted, the value get written in spreadsheet. Code for that is
function addData(form)
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sheet=ss.getSheetByName('test');
sheet.getRange(5,5).setValue(form.cName)
htmlPage();
}
All i want is once the value gets written on the sheet, this HTML page gets refreshed automatically. Right now it just stays as it is. Link to the HTML page is https://script.google.com/macros/s/AKfycbzavm6TPFOkIXj_V0uD8XIqMN-9w6jAgp_QgRkJXawFJF59rPU/exec

If you truly want to refresh the page, and not just clear the input field, then I would add a hidden link that has your web app URL, and then programatically "click" it when the server code has completed.
HTML
</form>
<a id="linkToThisWebApp" href="https://script.google.com/macros/s/webAppID/exec" style="display:none">Hidden</a>
<!-- <button onclick="reloadPg()">Test</button> -->
</div>
Script tag - Code with success handler
<script>
function addEventListeners() {
var condition=true;
document.getElementById('form1')
.addEventListener('submit',
function(e){
e.preventDefault();
if(condition==true){
condition=false;
google.script.run
.withSuccessHander(reloadPg)
.addData(this);
}
});
}
window.reloadPg = function() {//Runs when server code has completed
console.log('reloadPg ran');
document.getElementById('linkToThisWebApp').click();//Click the link
}
</script>

Related

how to call GAS functions in local html page

to demonstrate what im trying to do using a simple example:
<html>
<head>
<base target="_top">
</head>
<body>
<form id="uploaderForm" action="https://script.google.com/macros/.......exec Method="POST">
<input type="text" name="applicantName" id="applicantName">
<input type="text" name="applicantEmail" id="applicantEmail">
<input type="button" value="Submit">
</form>
<script>
.
.
.
google.script.run.withSuccessHandler(onFileUploaded)
.uploadFile(content, file.name, folderId);
</script>
so this is an example of the html and js page that is in my pc, not in the google app, i just called the google app in the form, and in the javascript part im calling a function called uploadFile, which is located in the google script, but obviously i get an error in the console , it says :
Uncaught ReferenceError: google is not defined
at uploadFiles (6166bff606ac6fee1994e592:67)
at HTMLInputElement.onclick
is it possible to call a GAS function inside JS that is not in the GAS html.
is what im trying to do even possible, the whoel reason im doing this is so that i can pass the username and email automatically from the database to the app, the app works if the html part is hosted in the google app script, but then i cant figure out how to pass the email and username to it because in this case i call the app using , so is it possible to pass the username and email through the iframe call, i dunno im very new to this i have so many questions, honestly the documentation wasn't helpful to me. please feel free to comment anything, everythign is helpful
Since you're just posting the form data, you can name the function you want to call as doPost()(instead of uploadFile) and it will receive the posted data. You have to republish the webapp as a new version after the modification.
I just ran it as a dialog. I returned the data back into the success handler and loaded by into the html to insure it was working.
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<body>
<form>
<input type="text" name="applicantName" id="applicantName"/>
<input type="text" name="applicantEmail" id="applicantEmail"/>
<input type="button" value="Submit" onclick="uploadfile(this.parentNode);" />
</form>
<div id="msg"></div>
<script>
function uploadfile(form) {
google.script.run
.withSuccessHandler((m) => document.getElementById("msg").innerHTML = m)
.uploadMyFile(form);
}
</script>
</body>
</html>
gs:
function uploadMyFile(obj) {
return `Applicant Name: ${obj.applicantName}<br />Applicant Email: ${obj.applicantEmail}`;
}
function launchFormDialog() {
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutputFromFile('ah2'),'Test Dialog');
}
Dialog:

How can I make a JQuery click event for all the buttons on my page?

I'm making a website settings page (I guess) where the user of the website can edit the page values that are seen on the public page of a website. (This is restricted to logged-in users only)
I have a form (shown below) that when clicked, executes AJAX and 'posts' the update content page.
I guess my question here is how can I change the code below so it changes which text body to take from based on the button pressed.
Even simpler, How can I make a page-wide click event that applies to all buttons, of which I can tell which button is pressed?
I know there is only 1 text field and 1 button below, but there are going to be more in the future, hence why I need this fuctionality.
My e.js file:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/admin.css">
<title>Manage the website</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#submitButton").click(function(){
$.ajax({
url: 'update',
type: 'POST',
data: {
toUpdate: 'homepage',
text: document.getElementById('textField').value // Select a text field based on the button
},
});
});
});
</script>
</head>
<header>
<!-- Put partial includes here -->
</header>
<div class="topPage">
<h1>Hello, <%= firstName %>!</h1>
<p1>
Find a value you would like to edit, then press send. The website can take up to 10 mins for the changes to apply. The changes will not change live.
</p1>
</div>
<div class="homepage">
<div class="information">
<h1>
Homepage variables
</h1>
<p1>
Variables for the 'homepage' page are displayed below. Changes can take up to 10 mins to apply globally.
</p1>
<hr>
</div>
<div class="form">
<label>
Change the 'body' of 'homepage'
</label>
<form action="nothing" method="post">
<input type="text" id="textField" name="text" value="<%= pageData.get('homepage').homeBody%>" required>
<button type="button" class="submit" id="submitButton">Submit Changes</button>
</form>
</div>
</div>
<script>
</script>
</html>
Thanks in advance!
You can do it like this:
$("button").on("click", function() {
console.log($(this).attr("id"));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="this">
This
</button>
<button id="that">
That
</button>
select the input tags in the form and track the change event:
$("form :input").on("change", function(){
var $elm = $(this); // the button which is clicked
// do your ajax here
});

Capturing input from a text input field in Google Aps script

I have a spreadsheet at work that contains information on various different devices we use.
The spreadsheet contains information like the Original Equipment Manufacturer, Storage capacity, format, Etc. There are a total of 10 Columns, and up to 359 rows currently; but the spreadsheet will expand from general use.
I have created a sidebar application in google sheets using Aps script and HTML, in order to make requesting support for these objects simpler. I am running in to an issue with capturing the data typed into an input field. Here is my HTML:
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<div class = "Container"><!-- Begin CONTAINER div -->
<div class="row"><!-- Begin ROW div -->
<div class="col s24 "><!-- Beginning of Header div -->
<h5 class="col s24"offset-s3> Edit a Kit </h5>
<div><!-- Text input field for Kit search -->
<div class="input-field col s12">
<textarea id="textarea1" class="materialize-textarea"></textarea>
<label for="textarea1">Enter Kit Name</label>
</div>
</div><!-- end of Text Input for Kit search -->
<!-- Start of Submit btn div -->
<div class="input-field col s12">
<button class="btn waves-effect waves-light" id="search" onclick ="submitData()">Search
<i class="material-icons right">search</i>
</button>
</div><!-- End of Submit btn div -->
<div class="divider"></div>
<div><!-- beginning of kit contents div -->
<!-- Users need to enter kit names into a text input field, similar to the create kit page -->
<h5 id = "kit" class = "section"></h5>
</div><!-- end of kit contents div -->
<div class="divider"></div>
<!-- Start of the HOME PAGE button Div -->
<div class="input-field col s12">
<button class="btn waves-effect waves-light" onclick="google.script.run.withSuccessHandler(changePage).newPage('Card Request Form')">Home
<i class="material-icons right">home</i>
</button>
</div><!-- end of the HOME PAGE button div -->
</div><!-- End of Header div --->
</div><!-- End of ROW Div -->
</div><!-- End of CONTAINER Div -->
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script>
function changePage(page) {
document.write(page);
}
// function alertA() {
// alert("Your code Failed to Run");
// };
function alertB() {
alert("Success! Click 'OK' to see your results");
};
function submitData() {
var data = document.getElementById('search').value;
var outPut = document.getElementById('kit');
var display = outPut.innerHtml = "THIS IS WORKING AS EXPECTED";
// alert(display);
};
function outputCard(submitData) {
};
</script>
</body>
</html>
I am trying to access the input data from the "Submit btn div" using the function "submitData()", but have been unsuccessful in doing so. In the version i've uploaded, I am simply trying to capture that information, and print it back out to the "kit contents div" but have been unsuccessful.
For clarity, I am doing this in a Google Apps scripts, as a sidebar extension to a google sheets spreadsheet. The goal is to take that input, and parse over the information for all of the informaton referenced in the first Full paragraph; and then return any items relevantr to the users search terms in the "kit contents div". I am not able to capture the input in Google Apps script though. Here is a copy of my gs code:
//This function searches for cards by the value typed into the text input field
function cardSearch(data) {
var app = SpreadsheetApp;
var log = app.openById("My Spreadsheet's ID");
var kitContents = app.openById("My Spreadsheet's ID");
var cards = log.getRange("A3:J").getValues();
var kitType = kitContents.getRange("A3:J359").getValues();
for (i=0; i<kitType[data]; i++){
return kitType[data];
}
Logger.log(kitType[356])
// for some reason, the array literal ends at index #356, where as the spreadsheet is up to 359 rows, but stops at ID#354
};
function alert(data) {
return "received input " +data.display;
};
//This function loads the webpage content of the HTML file "Card Request Form" as a sidebar in the main spreadsheet
function showRequestForm() {
var form = HtmlService.createTemplateFromFile("Card Request Form");
var html = form.evaluate();
SpreadsheetApp.getUi().showSidebar(html);
};
//This function allows us to navigate pages that exists in the document
function newPage(page) {
return HtmlService.createHtmlOutputFromFile(page).getContent()
};
I need help understanding how to cpature the input, and pass it back to the GS (I believe it's the same as passing it to the server) in order to run the cardSearch Function with that capturted data.
Here's an example form that I've used to collect receipt information. You can display it as a sidebar, a dialog or run it as a webapp. It has a numerical input, a text input and a textarea. It also allows you to upload a file.
thehtml.hmtl:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function(){
google.script.run
.withSuccessHandler(function(rObj){
$('#dt').val(rObj.date);
})
.initForm();
});
function fileUploadJs(frmData) {
var amt=$('#amt').val();
var vndr=$('#vndr').val();
var img=$('#img').val();
if(!amt){
window.alert('No amount provided');
$('#amt').focus();
return;
}
if(!vndr) {
window.alert('No vendor provided');
$('#vndr').focus();
return;
}
if(!img) {
window.alert('No image chosen');
$('#img').focus();
}
document.getElementById('status').style.display ='inline';
google.script.run
.withSuccessHandler(function(hl){
document.getElementById('status').innerHTML=hl;
})
.uploadTheForm(frmData)
}
console.log('My Code');
</script>
<style>
input,textarea{margin:5px 5px 5px 0;}
</style>
</head>
<body>
<h3 id="main-heading">Receipt Information</h3>
<div id="formDiv">
<form id="myForm">
<br /><input type="date" name="date" id="dt"/>
<br /><input type="number" name="amount" placeholder="Amount" id="amt" />
<br /><input type="text" name="vendor" placeholder="Vendor" id="vndr"/>
<br /><textarea name="notes" cols="40" rows="2" placeholder="NOTES"></textarea>
<br/>Receipt Image
<br /><input type="file" name="receipt" id="img" />
<br /><input type="button" value="Submit" onclick="fileUploadJs(this.parentNode)" />
</form>
</div>
<div id="status" style="display: none">
<!-- div will be filled with innerHTML after form submission. -->
Uploading. Please wait...
</div>
</body>
</html>
Codge.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('Receipt Collection')
.addItem('Run as Dialog', 'showAsDialog')
.addItem('Run as Sidebar', 'showAsSidebar')
.addToUi();
var sh=SpreadsheetApp.getActive().getSheetByName("Sheet1");
sh.getRange(sh.getLastRow()+1,1).activate();
}
function uploadTheForm(theForm) {
var rObj={};
rObj['vendor']=theForm.vendor;
rObj['amount']=theForm.amount;
rObj['date']=theForm.date;
rObj['notes']=theForm.notes
var fileBlob=theForm.receipt;
var fldr = DriveApp.getFolderById(receiptImageFolderId);
rObj['file']=fldr.createFile(fileBlob);
rObj['filetype']=fileBlob.getContentType();
Logger.log(JSON.stringify(rObj));
var cObj=formatFileName(rObj);
Logger.log(JSON.stringify(cObj));
var ss=SpreadsheetApp.openById(SSID);
ss.getSheetByName('Sheet1').appendRow([cObj.date,cObj.vendor,cObj.amount,cObj.notes,cObj.file.getUrl()]);
var html=Utilities.formatString('<br />FileName: %s',cObj.file.getName());
return html;
}
function formatFileName(rObj) {
if(rObj) {
Logger.log(JSON.stringify(rObj));
var mA=rObj.date.split('-');
var name=Utilities.formatString('%s_%s_%s.%s',Utilities.formatDate(new Date(mA[0],mA[1]-1,mA[2]),Session.getScriptTimeZone(),"yyyyMMdd"),rObj.vendor,rObj.amount,rObj.filetype.split('/')[1]);
rObj.file.setName(name);
}else{
throw('Invalid or No File in formatFileName() upload.gs');
}
return rObj;
}
function doGet() {
var output=HtmlService.createHtmlOutputFromFile('receipts').setTitle('thehtml');
return output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL).addMetaTag('viewport', 'width=360, initial-scale=1');
}
function showAsDialog() {
var ui=HtmlService.createHtmlOutputFromFile('thehtml');
SpreadsheetApp.getUi().showModelessDialog(ui, 'Receipts')
}
function showAsSidebar() {
var ui=HtmlService.createHtmlOutputFromFile('thehtml');
SpreadsheetApp.getUi().showSidebar(ui);
}
function initForm() {
var datestring=Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "yyyy-MM-dd")
return {date:datestring};
}
globals.gs:
var receiptImageFolderId='upload file folder id';
var SSID='spreadsheet id';

Passing parameters from Dialog to server side script

I have a Google sheet template. Each time this is opened, I would like to open a Dialog to get two parameters and pass those parameters to a script bound to the Google sheet template. So far I have managed to define and open the Dialog. But the parameters don't show up in the server side script.
It seems like readFormData is not called when I push the "Create" button. If I replace readFormData with google.script.host.close(), the dialog box will close down. But not with readFormData. The same problem goes with close(). So my take on this is the Java script does not execute.
EDIT: I have solved the problem with a workaround. I replaced onclick="readFormData" with onclick="google.script.run.withSuccessHandler(google.script.host.close).getFormData(this.parentNode)" and then everything work as expected. (required a few changes on GS side as well) However, I can't figure out why I can't call my own javascript procedure readFormData(). With help form Chrome Developer Tool I can notice readFormData is not defined, raising an exception "Uncaught ReferenceError: readFormData is not defined". It fires every time i click on the button. So I guess it must be a syntax error that fools the parser or similar.
GS:
function getFormData(obj) {
Logger.log(obj);
return "hello";
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Create file');
}
function onOpen(e) {
openDialog();
}
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet"
href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
<form id="getSomeData">
<div class="inline form-group">
<label for="fname">Destination</label>
<input type="text" name="fname" style="width: 150px;">
</div>
<div class="inline form-group">
<label for="date">Date</label>
<input type="text" name="date" style="width: 40px;">
</div>
<div>
<input type="button" class = "action" value= "Create" onclick="readFormData()" >
</div>
</form>
<!-- <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> -->
<script>
function success(msg) { // I have fixed the ((msg) error
alert(msg);
}
function readFormData(){
console.log("readFormData");
var form = document.getElementById("getSomeData").elements;
var obj ={};
for(var i = 0 ; i < form.length ; i++){
var item = form.item(i);
obj[item.name] = item.value;
}
google.script.run.withSuccessHandler(close).getFormData(obj);
}
function close(){
google.script.host.close();
}
</script>
</body>
</html>
It seems to me there is a misprint on "success" function which could lead to an interpretation problem :
success( ( msg).
Did you try without this "(" ?

Save form data to localstorage, display it in innerHTML and delete it with delete data button

I've got this code for saving form data into localstorage,then displaying it by replacing <span id="recalledtext" >Dear Visitors</span> with . innerHTML.
<HTML>
<head>
<script>
function myfunction1(){texttosave = document.getElementById('textline').value ; localStorage.setItem('mynumber', texttosave); } function myfunction2(){document.getElementById('recalledtext').innerHTML = localStorage.getItem('mynumber'); }
</script>
</head>
<body onload='myfunction2()'>
<input type="text" id="textline" placeholder="Enter Your Name"/> <button id="rememberer" onclick='myfunction1()'>Save</button>
<br>
Welcome<span id="recalledtext" >Dear Visitors</span> Refresh the page to see changes
</body>
</HTML>
It was working perfectly, but I also wanted a delete data button. So I've changed the code into this:
<HTML>
<head>
<script>
function myfunction1(){texttosave = document.getElementById('textline').value ; localStorage.setItem('mynumber', texttosave); } function myfunction2(){document.getElementById('recalledtext').innerHTML = localStorage.getItem('mynumber'); } function myfunction3() localStorage.removeItem('mynumber'); return '';}
</script>
</head>
<body onload='myfunction2()'>
<input type="text" id="textline" placeholder="Enter Your Name"/> <button id="rememberer" onclick='myfunction1()'>Save</button> <button id="recaller" onclick='myfunction3()'>Delete Your Name</button>
<br>
Welcome<span id="recalledtext" >Dear Visitors</span> Refresh the page to see changes
</body>
</HTML>.
But after adding function myfunction3() , the code was completely stopped working.
I've found the answer myself. I was for you a long time then I've started checking the JavaScript code. There was a missing character "{"
Here is the right code
<HTML><head>
<script>
function myfunction1(){texttosave = document.getElementById('textline').value ; localStorage.setItem('mynumber', texttosave); } function myfunction2(){document.getElementById('recalledtext').innerHTML = localStorage.getItem('mynumber'); } function myfunction3() localStorage.removeItem('mynumber'); return '';}
</script>
</head>
<body onload='myfunction2()'>
<input type="text" id="textline" placeholder="Enter Your Name"/> <button id="rememberer" onclick='myfunction1()'>remember text</button> <button id="recaller" onclick='myfunction3()'>Delete Your Name</button>
<br>
Welcome<span id="recalledtext" >Dear Visitors</span> Refresh the page to see changes
</body>
</HTML>