One of the most powerful aspects of using HTML Service in Google Apps Script is the ability to create dynamic web applications where the client-side (HTML, JavaScript running in the browser) and the server-side (your Apps Script code) can communicate with each other. This bidirectional communication allows you to fetch data from Google services, process it on the server, and then display it dynamically in your web app, or conversely, capture user input from the web app and use it to perform actions on the server.
Google Apps Script provides two primary methods for this communication: google.script.run for server-to-client calls and google.script.submit for client-to-server calls. Let's break down how each of these works.
Client-to-Server Communication: google.script.run
When your user interacts with your HTML Service web app (e.g., clicks a button, enters text), you often need to send that information to your Apps Script code running on Google's servers for processing. The google.script.run object, available in the client-side JavaScript of your HTML Service template, is your gateway to calling server-side Apps Script functions.
function sendDataToServer() {
var userInput = document.getElementById('myInput').value;
google.script.run.processUserInput(userInput);
}
// Attach this function to a button's onclick event in your HTMLIn this example, sendDataToServer is a client-side JavaScript function. When called, it reads a value from an input field and then uses google.script.run.processUserInput(userInput) to invoke a server-side function named processUserInput, passing the userInput as an argument. The processUserInput function must be defined in your Apps Script's .gs file.
function processUserInput(input) {
Logger.log('Received from client: ' + input);
// Perform server-side operations here, e.g., save to a Sheet
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().appendRow([input]);
return 'Data processed successfully!';
}Notice that the server-side function processUserInput can also return a value. This return value can be asynchronously handled back on the client-side, allowing for feedback or further client-side actions based on the server's response.
Handling Server Responses Asynchronously
When you call a server-side function using google.script.run, the call is asynchronous. This means your client-side JavaScript doesn't wait for the server to finish before continuing. To handle the response (or any errors), you can chain .withSuccessHandler() and .withFailureHandler() methods to your google.script.run calls.
function sendDataAndHandleResponse() {
var userInput = document.getElementById('myInput').value;
google.script.run
.withSuccessHandler(handleServerSuccess)
.withFailureHandler(handleServerError)
.processUserInput(userInput);
}
function handleServerSuccess(resultFromServer) {
alert('Server response: ' + resultFromServer);
// Update UI, clear input, etc.
document.getElementById('myInput').value = '';
}
function handleServerError(error) {
alert('An error occurred: ' + error.message);
}The handleServerSuccess function will be called with the return value from the server-side function. The handleServerError function will be called if any exception occurs during the server-side execution.
Server-to-Client Communication: google.script.host
Sometimes, you need to send data from your server-side Apps Script to your client-side HTML Service web app. This is particularly useful for pre-populating forms, fetching data to display, or updating the UI based on server-side logic.
The primary way to achieve this is by passing data as arguments to client-side functions when you first serve the HTML. You can also use google.script.run to call a server function that then calls a client function.
// In your .gs file
function doGet() {
var dataForClient = fetchDataFromServer();
var htmlTemplate = HtmlService.createTemplateFromFile('Index');
htmlTemplate.serverData = dataForClient; // Pass data to the template
return htmlTemplate.evaluate();
}
function fetchDataFromServer() {
// Simulate fetching data
return ['Item 1', 'Item 2', 'Item 3'];
}
// In your Index.html file (within a script tag)
<script>
var serverData = <?!= JSON.stringify(serverData) ?>;
console.log('Data from server:', serverData);
// Use serverData to populate UI elements
serverData.forEach(function(item) {
var li = document.createElement('li');
li.textContent = item;
document.getElementById('dataList').appendChild(li);
});
</script>
<ul id="dataList"></ul>In this approach, we use createTemplateFromFile and then set a property on the template (htmlTemplate.serverData). This property is then accessible in the client-side HTML within a script tag using <!= ... ?> for interpolation or <?!= ... ?> for safe HTML output. We use JSON.stringify to correctly pass JavaScript arrays or objects.
Alternatively, you can use google.script.run to call a server function, which then uses the client-side API to execute a client function with data. This is often referred to as a "callback" from the server.
// In your .gs file
function sendDataToClient() {
var serverMessage = 'Hello from the server!';
// Call a client-side function named 'displayMessage'
return google.script.run.withSuccessHandler(function(result) {
console.log('Client acknowledged:', result);
}).displayMessage(serverMessage);
}
// In your Index.html file (within a script tag)
function displayMessage(message) {
alert('Message from server: ' + message);
return 'Message displayed!'; // Return value for success handler
}Here, sendDataToClient is called from the client. It then calls a server-side function, which in turn calls a client-side function displayMessage using google.script.run.displayMessage(serverMessage). This is a slightly more indirect way but offers flexibility when you don't want to pass data directly through template variables.
Flow of Communication
Understanding the typical flow helps visualize the interaction:
- User Action (Client): The user interacts with an element in the web app (e.g., clicks a button).
- Client-Side JavaScript: An event handler is triggered, calling a JavaScript function.
- Call Server Function: The client-side function uses
google.script.runto invoke a server-side Apps Script function, passing any necessary data. - Server-Side Execution: The Apps Script function runs on Google's servers, performs logic, accesses Google services, and can optionally prepare a return value.
- Server Returns Data: The server-side function returns a value (or completes its execution).
- Client Receives Response: The
withSuccessHandler(orwithFailureHandler) on the client receives the data and executes the specified callback function. - Update UI (Client): The client-side callback function can then update the web app's interface, display information, or trigger further client-side actions.
sequenceDiagram
participant Client
participant Server
Client->>Server: Call server function (google.script.run)
Server-->>Client: Return value or status
alt Success
Client->>Client: Handle success response (withSuccessHandler)
else Failure
Client->>Client: Handle error response (withFailureHandler)
end
Mastering the communication between client and server is key to building truly interactive and powerful web applications with Google Apps Script. By effectively using google.script.run, you can bridge the gap and create seamless workflows.