Reputation: 764
Simplified the code as much as possible. How are the button clicks counted?
html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Example File 3</h1>
<form action="<?= url ?>" method="GET">
<input type="text" name="update" />
<input type="submit" name="Submit" /><br> <!-- count clicks -->
<span><?= update ?></span>
<span><?= count ?></span>
</form>
</body>
</html>
The Code.js file:
var clicks = 0;
function doGet(e) {
Logger.log(JSON.stringify(e));
var htmlOutput = HtmlService.createTemplateFromFile('ExampleFile3');
if (!e.parameter['update']) {
htmlOutput.update = '';
}
else {
htmlOutput.update = 'updated value is: ' + e.parameter['update'];
htmlOutput.count = 'count is: ' + clicks;
clicks++
}
htmlOutput.clicks = clicks;
htmlOutput.count = clicks;
htmlOutput.url = getUrl();
return htmlOutput.evaluate();
}
function getUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
the increment isn't increasing, that I see, and the output is squished together. Looking to count the number of form submissions.
Upvotes: 0
Views: 551
Reputation: 38346
Here is a sample code for creating an oversimplified web app. It shows one way to count button clicks using JavaScript.
HtmlOutput
object by using the HtmlService.HtmlOutput.append
method.<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>
.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:
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
Upvotes: 1