How do I pass a variable from GAS to HTML and back? - html

I am using GAS to create a web app. I have a doGet that generates the HTML page for the web app and a button on the web app that triggers a script. When I create the HTML page, there is a variable that I need to send to the web app that is then sent back to the script. That variable isn't used in the HTML page other than just transferring it.
Here is a minimal example of what I want to do:
My doGet() creates the HTML and passes the variable foo to the page
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile("page");
var foo = "12345";
htmlOutput.foo = foo;
return htmlOutput.evaluate().setTitle('Sample');
}
The HTML page has a button that, when clicked, should pass the variable foo back to GAS to run the function checkOut
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="btn" onclick="doStuff()">Click Here</button>
<script>
function doStuff(){
google.script.run.checkOut(foo);
}
</script>
</body>
</html>
In this example, checkOut just displays foo
function checkOut(foo){
Logger.log(foo);
}
I don't want foo displayed anywhere on the HTML page, but what should I add in order to get it sent back to GAS?
TIA

I believe your goal is as follows.
You want to use a value of foo in the function of checkOut at Google Apps Script side.
From That variable isn't used in the HTML page other than just transferring it. and I don't want foo displayed anywhere on the HTML page, you want to achieve this without including the value of foo in the HTML data.
In this case, how about the following modification?
Modified script 1:
In this modification, the value of foo is used with the scriptlets. This has already been mentioned in the comment.
In this method, the value of foo is shown in the HTML data like google.script.run.checkOut("12345"). I'm worried that this might not your expected situation from I don't want foo displayed anywhere on the HTML page. How about this?
Google Apps Script side:
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile("page");
var foo = "12345";
htmlOutput.foo = foo;
return htmlOutput.evaluate().setTitle('Sample');
}
function checkOut(foo){
Logger.log(foo);
}
HTML & Javascript side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="btn" onclick="doStuff()">Click Here</button>
<script>
function doStuff(){
google.script.run.checkOut("<?!= foo ?>");
}
</script>
</body>
</html>
Modified script 2:
In this modification, the value of foo is used as the background side (Google Apps Script side).
In this method, the value of foo is not shown in the HTML data.
Google Apps Script side:
function doGet(e) {
var foo = "12345";
PropertiesService.getScriptProperties().setProperty("sampleKey", foo);
var htmlOutput = HtmlService.createHtmlOutputFromFile("page");
return htmlOutput.setTitle('Sample');
}
function checkOut(){
var foo = PropertiesService.getScriptProperties().getProperty("sampleKey");
Logger.log(foo);
}
HTML & Javascript side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="btn" onclick="doStuff()">Click Here</button>
<script>
function doStuff(){
google.script.run.checkOut();
}
</script>
</body>
</html>
References:
HTML Service: Templated HTML
Properties Service

SUGGESTION
As what the TheWizEd has commented, you can also achieve your goal using the withSuccessHandler(). You may check this tweaked script below using a different implementation:
Code.gs
function doGet(e) {
var htmlOutput = HtmlService.createTemplateFromFile("page");
return htmlOutput.evaluate().setTitle('Sample');
}
function setupFoo(){ //Define a value for the "foo"
return "12345";
}
function checkOut(foo){
Logger.log(foo);
}
page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button id="btn" onclick="doStuff()">Click Here</button>
<script>
function onSuccess(foo) {
google.script.run.checkOut(foo); //on Success will pass back the foo value to GAS function "checkOut"
}
function doStuff(){
google.script.run.withSuccessHandler(onSuccess).setupFoo(); //Run "setupFoo" function & pass its returned value to the "withSuccessHandler" function named "onSuccess"
}
</script>
</body>
</html>
Demonstration
After clicking the Click Here button on the web app, checkOut will log the foo value:

Related

Trouble passing a variable to HTML from Google Apps Script and then back to GS again

Having trouble getting a parameter from the URL of a Web App deployed from Google App Script, passing it through a HTML template, and then getting it again as a parameter for a JS function when a user clicks on a button in the Web App.
Specifically, in the code below, I am having trouble passing the variable "username" from the html back to a JS function defined in my original Google App Script when the user clicks on the button "approveTC"...
Here is the Google Apps Script
function doGet(e) {
if(e.parameters.name === undefined){
var tmp = HtmlService.createTemplateFromFile('entername')
return tmp.evaluate();
} else {
var tmp = HtmlService.createTemplateFromFile('timecard')
tmp.username = e.parameters.name
return tmp.evaluate();
}
}
function timecardApproved(name){
return signAndSendTc(name)
}
And here is the HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include("timecard-css"); ?>
</head>
<body>
<div>
<h1>Hello <?!= username?></h1>
</div>
<div>
<iframe src=<?!= getTcJpg(username); ?> width="80%" height="800px" frameborder="0"></iframe>
</div>
<div>
<br>
<button id="approveTC">Approve Timecard</button>
</div>
<script>
document.getElementById("approveTC").addEventListener("click",approveTC);
function approveTC(username){
google.script.run.timecardApproved(username);
}
</script>
</body>
</html>
When you assign the templated value to a variable in your script, make sure that you pass it stringified
This works for me:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div>
<h1>Hello <?!= username?></h1>
</div>
<div>
</div>
<div>
<br>
<button id="approveTC">Approve Timecard</button>
</div>
<script>
var uname = "<?!= username ?>"
document.getElementById("approveTC").addEventListener("click",approveTC);
function approveTC() {
console.log(uname)
}
</script>
</body>
</html>
After a lot of experimenting, this was the solution that ended up working for me... very close to what #ziganotschka suggested. Except, when I tried #ziganotschka's method earlier, the variable didn't pass through correctly to my Google Apps Script. This code does work for me, though...
<script>
var username = <?= username ?>
document.getElementById("approveTC").addEventListener("click",approveTC);
function approveTC(){
google.script.run.timecardApproved(username);
}
</script>

GoogleSheets google.script.run always going to FailureHandler

I am using GoogleSheets HTMLService. I am calling google.script.run from my Html page's script. But it is always going to FailureHandler. What is wrong in it? Please see the code below. When I run it, it always shows the alert Failed. Also, the logger does not show any error. It is also not showing the console log "Inside Hello" in the hello() function. Do we also need to do some browser settings (I am using chrome - javascript allowed).
[UPDATED]
After replacing Logger.log with console.log, I am seeing it as Transport Error.
modeDialog.gs
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile("test");
html.setWidth(90).setHeight(1);
var ui = SpreadsheetApp.getUi().showModalDialog(html, "Opening ..." );
}
function hello() {
console.log("Inside Hello");
return "hello";
}
test.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(str) {
window.alert("executed");
}
function onFailure(error) {
window.alert("failed");
Logger.log(error);
}
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).hello();
</script>
</head>
<body>
<div id="failureContent"></div>
Hello world
</body>
</html>
As I mentioned that it was working earlier in Chrome and is currently working in FireFox, I tested it again after changing my chrome settings to default by going to Chrome > Settings > Advanced > Reset and clean up > Restore settings to their original defaults.
It is working fine after that. So setting this as the answer.
I ran it this way:
GS:
function openDialog() {
SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile("ah3"), "Opening ..." );
}
function hello() {
return "hello";
}
HTML:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Hello world
<script>
window.onload=function(){
google.script.run
.withSuccessHandler(function(str){window.alert("executed");})
.withFailureHandler(function(error){window.alert("failed");})
.hello();
}
console.log('MyCode');
</script>
</body>
</html>
I just like to use onReadyState function or onload to run most javascript so that html is already loaded. Not that it makes much difference in this trivial example. Also I tend to put the scripts in the body rather than in the head.

How to send inputs from google spreadsheet sidebar into sheet script function?

I want to have 3 text fields with labels and a button on sidebar, clicking the button should send content of text fields to spreadsheet script function for further processing. I know how to create and display the sidebar, also how to trigger script function with button click but have no idea how to send text fields content.
// SidePanel.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button onclick='f1()'>Update the address</button>
<script>
function f1() {
google.script.run.getAddress();
}
</script>
</body>
</html>
// display sidebar in gs
function showSidebar(){
var html = HtmlService.createHtmlOutputFromFile('SidePanel').setTitle('Helper').setWidth(100);
SpreadsheetApp.getUi().showSidebar(html);
}
Here is an example that will help you understand how to send values from the sidebar to the google sheet
Html Code:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<button onclick='f1()'>Update the address</button>
<!-- Create a input field to except a value form user, in this case there name -->
Your Name:
<input type="text" id="name"><br>
<!-- Create a button to send the value to the spreadsheet -->
<button onclick='sendName()'>Send Name</button>
<script>
function f1() {
google.script.run.getAddress();
}
function sendName(){
//Get the value of the input field
var name = document.getElementById("name").value
//Log the value of input field in the web browser console (usually used for debugging)
console.log(name)
//Send the value of the text field as a arugment to the server side function.
google.script.run.enterName(name)
}
</script>
</body>
</html>
The HTML code above use the input field to get values from the user. You can access the value of the input field using DOM methods. The value of the text field is stored in the var name in function sendNames(). This is passed to the google script function as an argument google.script.run.enterName(name).
Your google script (aka server-side code)
function showSidebar(){
var html = HtmlService.createHtmlOutputFromFile('SO_sideBar_Example').setTitle('Helper').setWidth(100);
SpreadsheetApp.getUi().showSidebar(html);
}
// Sets the value of A1 cell to value entered in the input field in the side bar!
function enterName(name){
var ss = SpreadsheetApp.getActive()
var sheet = ss.getActiveSheet()
sheet.getRange("A1").setValue(name)
}
In the above server side code,function enterName() receives the user input in the argument name, which is entered in cell A1.
It is good practice to use withSuccessHandler() and withFailureHandler() as detailed here. To handle the success or failure of the server side code.

Google apps script get user input with no length limit

I want to take user input (HTML specifically) using either:
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Paste HTML below');
or
var input = Browser.inputBox('Paste HTML below', Browser.Buttons.OK_CANCEL);
These work fine for small inputs, however when copying over the entire HTML for a page of interest an error occurs (in each case). This error cannot be caught, it simply crashes the script.
Do you know why this is happening? I can't find anything in the docs that mention limits on input size.
Any experience doing this a different way?
Edit: as per a suggestion in the comments, I have tried another method (below). This also fails (with no error message) when passed large input.
First I set up Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
Paste Sitemap Content Below
<textarea id="user-input-box" rows="4" cols="50"></textarea>
<script>
function logToConsole() {
var userInput = document.getElementById("user-input-box").value;
google.script.run.doSomething(userInput);
}
</script>
<input type="button" value="Close" onclick="logToConsole();google.script.host.close();" />
</body>
</html>
Then in file Code.gs
function testDialog() {
var html = HtmlService.createHtmlOutputFromFile('Page')
.setWidth(400)
.setHeight(300);
SpreadsheetApp.getUi()
.showModalDialog(html, 'My custom dialog');
}
function doSomething(userInput){
Logger.log(userInput);
}
I just ran into the same problem and couldn't log the error. In my case as is yours, you're calling your logToConsole() function and then directly after you're closing the dialog by using google.script.host.close();
google.script.host.close() is the problem. For some reason it can cancel the script execution - this typically happens when you're sending a lot of data back. The trick is to use a successHandler when you call your script which then calls google.script.host.close(). This way, the data transfer from the dialog finishes correctly and when you call withSuccessHandler(), that callback closes the dialog. Try this amendment to your code:
<script>
function logToConsole() {
var userInput = document.getElementById("user-input-box").value;
google.script.run.withSuccessHandler(closeDialog).doSomething(userInput);
}
function closeDialog() {
google.script.host.close();
}
</script>
<input type="button" value="Close" onclick="logToConsole()" />

Create a Google Form in Pop up of Google Spreadsheet. Could this be done?

Reference :
Single Google Form for multiple Sheets
Re-claim :
I have a little bit hard to made my writing some good or as well to
be understanding (less english).
I have a little insight about a Google Apps Script (GAS).
I have change "MyURLDoc" and "MyIdDoc" bellow as cosinderring of
mine.
Question :
How do I make a Google Form be inside of a Pop up what I've made in Google Spreadsheet ?
Attempt 1 :
function goToURL() {
FormApp.openByUrl(//*** MyURLDoc! ***//);
}
Attempt 2 :    
Following as the reference has worte there!
function goToForm() {
var form = FormApp.openById(//*** MyIdDoc! ***//),
    formUrl = form.getPublishedUrl(),
    response = UrlFetchApp.fetch(formUrl),
    formHtml = response.getContentText(),
    htmlApp = HtmlService
.createHtmlOutput(formHtml)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Ta Daaa!')
.setWidth(500)
.setHeight(450); SpreadsheetApp.getActiveSpreadsheet().show(htmlApp);
}
Problem :
It says always like this:     " No item with the given ID could be found or You do not have permission "
Creating a Sidebar with a Google Form
I just went to an old form I have and got the embed code. I loaded into a sidebar that I had on another project and pasted the embed code which is an iframe and it loaded perfectly except for the size and I ran the form and sure enough it loaded data into the spreadsheet that contains it.
I thought I'd go ahead and add a complete example. This is a simple example which creates a form for inputting time stamped text into a spreadsheet. It's done two ways. The first technique uses standard html, javascript, JQuery and Google Script. The second technique is accomplished by just creating a form and embedding it into a simple html page. Both versions fit into the side bar and both are linked to spreadsheet pages where the text is loaded and timestamped.
Code.gs:
function onOpen()
{
SpreadsheetApp.getUi().createMenu('My Tools')
.addItem('createTextEntryForm', 'createTextEntryForm')
.addToUi();
loadSideBar();
SpreadsheetApp.getUi().createMenu('My Menu').addItem('loadSidebar', 'loadSideBar').addToUi();
}
//This loads the text into the spreadsheet for the html version of the form.
function dispText(txt)
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var sht=ss.getSheetByName('Notes');
var ts=Utilities.formatDate(new Date(), 'GMT-6', "M/dd/yyyy HH:mm:ss");
var row=[];
row.push(ts);
row.push(txt);
sht.appendRow(row);
return true;
}
function loadSideBar()
{
var userInterface=HtmlService.createHtmlOutputFromFile('formBar');//sidebar for html and formBar for form
SpreadsheetApp.getUi().showSidebar(userInterface);
}
//This is the form
function createTextEntryForm()
{
var ss=SpreadsheetApp.getActiveSpreadsheet();
var form=FormApp.create('Form On A Sidebar');
form.setDescription('Enter Your Message and Push Submit when complete.')
.setConfirmationMessage('Message Saved and TimeStamped.')
.setAllowResponseEdits(true)
.setAcceptingResponses(false)
.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId());
var containerLink=form.addParagraphTextItem();
containerLink.setTitle('Enter your comment now.')
.isRequired();
}
sidebar.html which is the html version of the form:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(function() {
$('#txt1').val('');
});
function sendText()
{
var txt=$('#txt1').val();
google.script.run
.withSuccessHandler(clearText)
.dispText(txt);
}
function clearText()
{
$('#txt1').val('');
}
console.log("My code");
</script>
</head>
<body>
<textarea id="txt1" rows="12" cols="35"></textarea>
<br />
<input id="btn1" type="button" value="submit" onClick="sendText();" />
</body>
</html>
formBar.html is where the form is embedded:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<iframe src="FormURL?embedded=true#start=embed" width="300" height="550" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>
</body>
</html>
This is what the spreadsheet and sidebars look like: