google.script.run es una API de JavaScript asíncrona del cliente que permite que las páginas de servicio HTML llamen a funciones de Apps Script del servidor. En el siguiente ejemplo, se muestra la funcionalidad más básica de google.script.run: llamar a una función en el servidor desde JavaScript del cliente.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function doSomething() {
Logger.log('I was called!');
}Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
google.script.run.doSomething();
</script>
</head>
</html>Si implementas esta secuencia de comandos como una app web y visitas su URL, no verás nada, pero si consultas los registros, verás que se llamó a la función del servidor doSomething.
Las llamadas del cliente a las funciones del servidor son asíncronas: después de que el navegador solicita que el servidor ejecute la función doSomething, el navegador continúa inmediatamente con la siguiente línea de código sin esperar una respuesta. Esto significa que es posible que las llamadas a funciones del servidor no se ejecuten en el orden que esperas. Si realizas dos llamadas a funciones al mismo tiempo, no hay forma de saber qué función se ejecuta primero. El resultado puede variar cada vez que cargues la página. En esta situación, los controladores de éxito y los controladores de errores ayudan a controlar el flujo de tu código.
La API de google.script.run permite 10 llamadas simultáneas a las funciones del servidor. Si realizas una 11ª llamada mientras aún se ejecutan 10, la función del servidor se demora hasta que se libere uno de los 10 lugares. En la práctica, rara vez deberías pensar en esta restricción, sobre todo porque la mayoría de los navegadores ya limitan la cantidad de solicitudes simultáneas al mismo servidor a una cantidad inferior a 10.
En Firefox, por ejemplo, el límite es de 6. La mayoría de los navegadores también retrasan las solicitudes excesivas del servidor hasta que se completa una de las solicitudes existentes.
Parámetros y valores de muestra
Llama a una función del servidor con parámetros del cliente. Del mismo modo, una función del servidor puede devolver un valor al cliente como un parámetro que se pasa a un controlador de éxito.
Los parámetros y valores de devolución legales son primitivos de JavaScript, como Number, Boolean, String o null, así como objetos y arrays de JavaScript compuestos por primitivos, objetos y arrays. Un elemento form dentro de la página también es válido como parámetro, pero debe ser el único parámetro de la función y no es válido como valor de retorno. Las solicitudes fallan si intentas pasar un elemento Date, Function, DOM que no sea un form o algún otro tipo prohibido, incluidos los tipos prohibidos dentro de objetos o arrays. Los objetos que crean referencias circulares también fallan, y los campos indefinidos dentro de los arrays se convierten en null.
Ten en cuenta que un objeto que se pasa al servidor se convierte en una copia del original. Si una función del servidor recibe un objeto y cambia sus propiedades, las propiedades del cliente no se ven afectadas.
Controladores de éxito
Como las llamadas a google.script.run son asíncronas, el código del cliente continúa a la siguiente línea sin esperar una respuesta. Para especificar una función de devolución de llamada que se ejecute cuando el servidor responda, usa withSuccessHandler(function).
Si la función del servidor devuelve un valor, la API pasa ese valor a la función de devolución de llamada como un parámetro.
En el siguiente ejemplo, se muestra una alerta del navegador cuando responde el servidor. Este ejemplo de código requiere autorización porque la función del servidor accede a tu cuenta de Gmail. Para autorizar la secuencia de comandos, ejecuta la función getUnreadEmails manualmente desde el editor de secuencias de comandos una vez antes de cargar la página. Como alternativa, cuando implementas la app web para que se ejecute como el "usuario que accede a la app web", se te solicita autorización cuando cargas la app.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getUnreadEmails() {
return GmailApp.getInboxUnreadCount();
}Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(numUnread) {
var div = document.getElementById('output');
div.innerHTML = 'You have ' + numUnread
+ ' unread messages in your Gmail inbox.';
}
google.script.run.withSuccessHandler(onSuccess)
.getUnreadEmails();
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>Controladores de errores
Si el servidor no responde o arroja un error, withFailureHandler(function) te permite especificar un controlador de errores para que se ejecute en lugar de un controlador de éxito.
Si se produce un error, la API pasa el objeto Error como argumento al controlador de errores.
De forma predeterminada, si no especificas un controlador de errores, estos se registran en la consola de JavaScript. Para anular este comportamiento, llama a withFailureHandler(null) o proporciona un controlador de errores que no haga nada.
La sintaxis de los controladores de errores es casi idéntica a la de los controladores de éxito, como se muestra en este ejemplo.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getUnreadEmails() {
// 'got' instead of 'get' throws an error.
return GmailApp.gotInboxUnreadCount();
}Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onFailure(error) {
var div = document.getElementById('output');
div.innerHTML = "ERROR: " + error.message;
}
google.script.run.withFailureHandler(onFailure)
.getUnreadEmails();
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>Objetos de usuario
Para volver a usar el mismo controlador de éxito o error para varias llamadas al servidor, llama a withUserObject(object) para especificar un objeto que se pase al controlador como segundo parámetro.
Este "objeto de usuario", que no debe confundirse con la clase User, te permite responder al contexto en el que el cliente se comunicó con el servidor. Como los objetos de usuario no se envían al servidor, pueden ser casi cualquier cosa, incluidas funciones y elementos DOM, sin las restricciones en los parámetros y los valores de retorno para las llamadas al servidor. Los objetos de usuario no pueden ser objetos construidos con el operador new.
En este ejemplo, hacer clic en cualquiera de los dos botones actualiza ese botón con un valor del servidor y deja el otro botón sin cambios, aunque compartan un controlador de éxito. Dentro del controlador onclick, la palabra clave this hace referencia al propio button.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getEmail() {
return Session.getActiveUser().getEmail();
}Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function updateButton(email, button) {
button.value = 'Clicked by ' + email;
}
</script>
</head>
<body>
<input type="button" value="Not Clicked"
onclick="google.script.run
.withSuccessHandler(updateButton)
.withUserObject(this)
.getEmail()" />
<input type="button" value="Not Clicked"
onclick="google.script.run
.withSuccessHandler(updateButton)
.withUserObject(this)
.getEmail()" />
</body>
</html>Formularios
Si llamas a una función del servidor con un elemento form como parámetro, el formulario se convierte en un solo objeto con nombres de campo como claves y valores de campo como valores. Todos los valores se convierten en cadenas, excepto el contenido de los campos de entrada de archivos, que se convierten en objetos Blob.
En este ejemplo, se procesa un formulario, incluido un campo de entrada de archivo, sin volver a cargar la página. Se sube el archivo a Google Drive y, luego, se imprime la URL del archivo en la página del cliente. Dentro del controlador onsubmit, la palabra clave this hace referencia al formulario en sí. Ten en cuenta que, cuando se cargan todos los formularios de la página, la acción de envío predeterminada está inhabilitada por preventFormSubmit. Esto evita que la página redireccione a una URL inexacta en caso de que se produzca una excepción.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function processForm(formObject) {
var formBlob = formObject.myFile;
var driveFile = DriveApp.createFile(formBlob);
return driveFile.getUrl();
}Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(updateUrl).processForm(formObject);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = '<a href="' + url + '">Got it!</a>';
}
</script>
</head>
<body>
<form id="myForm" onsubmit="handleFormSubmit(this)">
<input name="myFile" type="file" />
<input type="submit" value="Submit" />
</form>
<div id="output"></div>
</body>
</html>Ejecutores de secuencias de comandos
Piensa en google.script.run como un compilador para un "ejecutor de secuencias de comandos". Si agregas un controlador de éxito, un controlador de errores o un objeto de usuario a un ejecutor de secuencias de comandos, no cambiarás el ejecutor existente. En cambio, obtendrás un nuevo ejecutor de secuencias de comandos con un comportamiento nuevo.
Usa cualquier combinación y orden de withSuccessHandler, withFailureHandler y withUserObject. También llama a cualquiera de las funciones de modificación en un ejecutor de secuencias de comandos que ya tenga un valor establecido. El valor nuevo reemplaza al anterior.
En este ejemplo, se establece un controlador de errores común para las tres llamadas al servidor, pero dos controladores de éxito separados:
var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);
myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();
Funciones privadas
Las funciones del servidor cuyos nombres terminan con un guion bajo se consideran privadas.
google.script no puede llamar a estas funciones, y sus nombres nunca se envían al cliente. Puedes usarlos para ocultar detalles de implementación que deben mantenerse secretos en el servidor. google.script tampoco puede ver funciones dentro de bibliotecas ni funciones que no se hayan declarado en el nivel superior de la secuencia de comandos.
En este ejemplo, la función getBankBalance está disponible en el código del cliente. Un usuario que inspeccione tu código fuente puede descubrir su nombre incluso si no la llamas. Sin embargo, las funciones deepSecret_ y obj.objectMethod son completamente invisibles para el cliente.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getBankBalance() {
var email = Session.getActiveUser().getEmail()
return deepSecret_(email);
}
function deepSecret_(email) {
// Do some secret calculations
return email + ' has $1,000,000 in the bank.';
}
var obj = {
objectMethod: function() {
// More secret calculations
}
};Index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
function onSuccess(balance) {
var div = document.getElementById('output');
div.innerHTML = balance;
}
google.script.run.withSuccessHandler(onSuccess)
.getBankBalance();
</script>
</head>
<body>
<div id="output">No result yet...</div>
</body>
</html>Cambia el tamaño de los diálogos en las aplicaciones de Google Workspace
Se puede cambiar el tamaño de los cuadros de diálogo personalizados en Documentos, Hojas de cálculo o Formularios de Google llamando a los métodos google.script.host, setWidth(width) o setHeight(height) en el código del cliente. (Para establecer el tamaño inicial de un diálogo, usa los métodos HtmlOutput setWidth(width) y setHeight(height)). Ten en cuenta que los diálogos no se vuelven a centrar en la ventana principal cuando se cambia su tamaño, y no es posible cambiar el tamaño de las barras laterales.
Cómo cerrar diálogos y barras laterales en Google Workspace
Si usas el servicio HTML para mostrar un diálogo o una barra lateral en Documentos, Hojas de cálculo o Formularios de Google, no puedes cerrar la interfaz llamando a window.close. En su lugar, debes llamar a google.script.host.close.
Para ver un ejemplo, consulta la sección sobre cómo publicar HTML como una interfaz de usuario de Google Workspace.
Cómo mover el enfoque del navegador en Google Workspace
Para cambiar el enfoque en el navegador del usuario de un diálogo o una barra lateral al editor de Documentos, Hojas de cálculo o Formularios de Google, llama al método google.script.host.editor.focus.
Este método es particularmente útil en combinación con los métodos Document.setCursor(position) y Document.setSelection(range) del servicio Document.