Here is a sample code for creating an oversimplified web app. It shows one way to count button clicks using JavaScript.
- The client-side code is added to the
HtmlOutput
object by using the HtmlService.HtmlOutput.append
method.
- The global variable is set in the client-side instead of the server-side. Please bear in mind that reloading the web app will reset the global variable.
- In
<form>
uses the attribute onsubmit
instead of the attributes action and method. This attribute calls a client-side JavaScript function that updates the client-side global variable and display it in <div>
.
- Please note the use of
event.preventDefault()
. This is required when submitting html forms in Google Apps Script web apps because the form is hosted in a special Google service that cannot be modified by the Google Apps Script web app developers.
function doGet(e) {
return HtmlService.createHtmlOutput()
.append(`
<form onsubmit="handleFormSubmit()">
<input type="text" name="something"><br>
<button type="submit">Submit</button>
</form>
<div>0</div>
<script>
var clicks = 0;
function handleFormSubmit(){
event.preventDefault();
document.querySelector('div').innerHTML = ++clicks;
}
</script>
`);
}
Notes:
- The web browser console will show several warnings. You can ignore them
- The web browser console will show the following error:
Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.
at gas-hub.js:25:10
For the purpose of this oversimplified example, you can ignore it. To avoid this error, the HtmlOutput
object should include a "full" HTML5 structure:
function doGet(e) {
return HtmlService.createHtmlOutput()
.append(`
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form onsubmit="handleFormSubmit()">
<input type="text" name="something"><br>
<button type="submit">Submit</button>
</form>
<div>0</div>
<script>
var clicks = 0;
function handleFormSubmit(){
event.preventDefault();
document.querySelector('div').innerHTML = ++clicks;
}
</script>
</body>
</html>
`)
.setTitle('Demo')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
To send <form>
values to the server side, as well for other type of values, without reloading the web app, use google.script.run
to call a server side function as is explained in https://developers.google.com/apps-script/guides/html/communication.
You also can use google.script.run
to call server side functions on client-side event like clicking button. A very simple way is by using a button (<button>
or <input type="button">
with an onclick attribute).
<button onclick="google.script.run.myFunction();">Run</button>
Also it's possible to use it with <form>
's onsubmit
attribute and buttons of type submit but you have to include event.preventDefault()
to avoid the page redirection cause the form submit action.
Please bear in mind that the use of event attributes is discouraged. Instead set the function to be called on the event by using HtmlElement.addEventListener
whenever be possible.
To store a value persistently, do not use server-side global variables, instead consider to use the Properties Service among other options (see the related questions).
Here is another example, now using the "full" HTML5 structure, the Properties Service to persistently keep the number of button clicks. Instead of using the attribute onsubmit
it uses the <form>
attributes action
and method
but also use <base>
to set the elements target to `"_top". This is required to properly reload the web app when the form is submitted.
A hidden <input>
is used to pass a value to control when the click counter should be increased, this way we prevent that following the link (without the clicked=yes
url parameter) increase the counter. Please note that no JavaScript is included on the client-side (HtmlOutput).
function doGet(e) {
const props = PropertiesService.getScriptProperties();
const name = "clicks";
let clicks = Number(props.getProperty(name));
if (e && e.parameter && e.parameter.clicked === 'yes') {
props.setProperty(name, ++clicks);
}
return HtmlService.createHtmlOutput()
.append(`
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<form action="${ScriptApp.getService().getUrl()}" method="GET">
<input type="hidden" name="clicked" value="yes">
<input type="text" name="something" value="default value"><br>
<button type="submit">Submit</button>
</form>
<div>${clicks}</div>
</body>
</html>
`)
.setTitle('Demo')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
If you are on your way to create a production class web application, please be aware that the client-side code is "satinized" and there are some limitations about what can done compared to other platforms. Please study the references to learn the basics about this.
Related
References