google.script.run
é uma API JavaScript assíncrona
do lado do cliente que permite que páginas de serviço HTML chamem funções do Apps Script
do lado do servidor. O exemplo a seguir mostra a funcionalidade mais básica
de google.script.run
:
chamando uma função no servidor
do JavaScript do lado do 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>
Se você implantar esse script como um app da Web e acessar o URL dele, não vai aparecer
nada, mas, se você consultar os registros, vai notar que a função do servidor
doSomething()
foi chamada.
As chamadas do lado do cliente para funções do lado do servidor são assíncronas: depois que o navegador
solicita que o servidor execute a função doSomething()
, ele continua
imediatamente para a próxima linha de código sem esperar por uma resposta. Isso significa
que as chamadas de função do servidor podem não ser executadas na ordem esperada. Se você fizer
duas chamadas de função ao mesmo tempo, não vai ser possível saber qual função será
executada primeiro. O resultado pode ser diferente a cada vez que você carrega a página. Nessa situação,
gerenciadores de sucesso e gerenciadores de falha
ajudam a controlar o fluxo do código.
A API google.script.run
permite 10 chamadas simultâneas para funções do servidor. Se
você fizer uma 11ª chamada enquanto 10 ainda estiverem em execução, a função do servidor será
adiada até que um dos 10 lugares seja liberado. Na prática, raramente você precisará
pensar nessa restrição, especialmente porque a maioria dos navegadores já limita
o número de solicitações simultâneas para o mesmo servidor a um número inferior a 10.
No Firefox, por exemplo, o limite é 6. A maioria dos navegadores também atrasa o excesso
de solicitações do servidor até que uma das solicitações atuais seja concluída.
Parâmetros e valores de retorno
É possível chamar uma função do servidor com parâmetros do cliente. Da mesma forma, uma função do servidor pode retornar um valor ao cliente como um parâmetro transmitido para um gerenciador de sucesso.
Parâmetros legais e valores de retorno são primitivos do JavaScript, como Number
, Boolean
, String
ou null
, além de objetos e matrizes do JavaScript que
são compostos de primitivos, objetos e matrizes. Um elemento form
na página
também é válido como parâmetro, mas precisa ser o único parâmetro da função e
não pode ser usado como valor de retorno. As solicitações falham se você tentar transmitir um
Date
, Function
, elemento DOM além de um form
ou outro tipo proibido,
incluindo tipos proibidos em objetos ou matrizes. Objetos que criam
referências circulares também falharão, e campos indefinidos em matrizes se tornarão
null
.
Um objeto transmitido ao servidor se torna uma cópia do original. Se uma função do servidor receber um objeto e mudar as propriedades dele, as propriedades do cliente não serão afetadas.
Manipuladores de sucesso
Como o código do lado do cliente continua para a próxima linha sem esperar que uma chamada
do servidor seja concluída,
withSuccessHandler(function)
permite que você especifique uma função de callback do lado do cliente para ser executada quando o servidor
responder. Se a função do servidor retornar um valor, a API vai transmitir o valor para
a nova função como um parâmetro.
O exemplo a seguir mostra um alerta do navegador quando o servidor responde. Observe
que este exemplo de código exige autorização porque a função do lado do servidor está
acessando sua conta do Gmail. A maneira mais simples de autorizar o script é executar
a função getUnreadEmails()
manualmente no editor de script uma vez antes de
carregar a página. Como alternativa, ao
implantar o app da Web, você pode escolher
executar como "usuário acessando o app da Web". Nesse caso, você vai receber uma solicitação de autorização ao carregar o 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>
Gerenciadores de falhas
Caso o servidor não responda ou gere um erro,
withFailureHandler(function)
permite especificar um gerenciador de falha em vez de um gerenciador de sucesso, com o
objeto Error
(se houver) transmitido como um argumento.
Por padrão, se você não especificar um manipulador de falhas, elas serão registradas no
console do JavaScript. Para substituir isso, chame withFailureHandler(null)
ou forneça
um gerenciador de falha que não faça nada.
A sintaxe dos gerenciadores de falha é quase idêntica aos gerenciadores de sucesso, como mostra este exemplo.
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function getUnreadEmails() { // 'got' instead of 'get' will throw 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 do usuário
É possível reutilizar o mesmo gerenciador de sucesso ou falha para várias chamadas ao
servidor chamando
withUserObject(object)
para especificar um objeto que será transmitido ao gerenciador como um segundo parâmetro.
Esse "objeto de usuário", que não deve ser confundido com a
classe User
, permite responder ao
contexto em que o cliente entrou em contato com o servidor. Como os objetos do usuário não são
enviados ao servidor, eles podem ser quase tudo, incluindo funções, elementos
DOM e assim por diante, sem as restrições de parâmetros e valores de retorno
para chamadas de servidor. No entanto, os objetos de usuário não podem ser objetos construídos com o
operador new
.
Neste exemplo, clicar em um dos dois botões atualiza esse botão com um
valor do servidor, deixando o outro botão inalterado, mesmo que eles
compartilhem um manipulador de sucesso. No gerenciador onclick
, a palavra-chave this
se refere ao próprio 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>
Formulários
Se você chamar uma função do servidor com um elemento form
como parâmetro, o formulário
se tornará um único objeto com nomes de campo como chaves e valores de campo como valores. Todos os
valores são convertidos em strings, exceto o conteúdo dos campos de entrada de
arquivo, que se tornam objetos Blob
.
Este exemplo processa um formulário, incluindo um campo de entrada de arquivo, sem recarregar
a página. Ele faz upload do arquivo no Google Drive e imprime o URL do
arquivo na página do lado do cliente. No manipulador onsubmit
, a palavra-chave this
se refere ao formulário. Ao carregar, todos os formulários na página têm
a ação de envio padrão desativada por preventFormSubmit
. Isso impede que a
página redirecione para um URL incorreto em caso de exceção.
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>
Executores de script
Pense em google.script.run
como um builder para um "script runner". Se você
adicionar um manipulador de sucesso, um manipulador de falha ou um objeto de usuário a um script runner, não
estará mudando o runner existente. Em vez disso, você vai receber um novo script runner
com um novo comportamento.
É possível usar qualquer combinação e ordem de withSuccessHandler()
,
withFailureHandler()
e withUserObject()
. Também é possível chamar qualquer uma das
funções modificadoras em um executor de script que já tenha um valor definido. O novo
valor simplesmente substitui o anterior.
Este exemplo define um gerenciador de falhas comum para as três chamadas de servidor, mas dois gerenciadores de sucesso separados:
var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);
myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();
Funções particulares
As funções do servidor cujos nomes terminam com um sublinhado são consideradas particulares.
Essas funções não podem ser chamadas por google.script
, e os nomes delas nunca são
enviados ao cliente. Assim, é possível usá-los para ocultar detalhes de implementação que
precisam ser mantidos em segredo no servidor. O google.script
também não consegue ver
funções em bibliotecas e funções que não são
declaradas no nível superior do script.
Neste exemplo, a função getBankBalance()
está disponível no código
do cliente. Um usuário que inspeciona o código-fonte pode descobrir o nome dela, mesmo que você
não a chame. No entanto, as funções deepSecret_()
e obj.objectMethod()
são completamente invisíveis para
o 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>
Redimensionar caixas de diálogo em aplicativos
As caixas de diálogo personalizadas nos apps Documentos, Planilhas ou
Formulários Google podem ser redimensionadas chamando os métodos
google.script.host
setWidth(width)
ou
setHeight(height)
no
código do lado do cliente. Para definir o tamanho inicial de uma caixa de diálogo, use os métodos
HtmlOutput
setWidth(width)
e
setHeight(height)
.
As caixas de diálogo não são centralizadas novamente na janela pai quando redimensionadas, e não
é possível redimensionar as barras laterais.
Fechar caixas de diálogo e barras laterais em
Se você usar o serviço HTML para mostrar uma
caixa de diálogo ou barra lateral nos Documentos, Planilhas ou
Formulários Google, não será possível fechar a interface chamando window.close()
. Em vez disso, chame
google.script.host.close()
.
Para conferir um exemplo, consulte a seção sobre
como servir HTML como uma interface do usuário.
Como mover o foco do navegador em
Para mudar o foco no navegador do usuário de uma caixa de diálogo ou barra lateral para o
editor de Documentos, Planilhas ou Formulários Google, basta chamar o método
google.script.host.editor.focus()
.
Esse método é útil principalmente em combinação com os métodos
Document service
Document.setCursor(position)
e
Document.setSelection(range)
.