google.script.run は、HTML サービスページからサーバーサイドの Apps Script
関数を呼び出すことができる非同期のクライアントサイド JavaScript API です。次の例は、最も基本的な
機能(google.script.run — クライアントサイド
JavaScript からサーバー上の関数を呼び出す)を示しています。
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>このスクリプトをウェブアプリとしてデプロイしてその URL にアクセスしても何も表示されませんが、ログを表示すると、サーバー関数 doSomething が呼び出されたことがわかります。
サーバーサイド関数へのクライアントサイド呼び出しは非同期です。ブラウザがサーバーに doSomething
関数の実行をリクエストすると、ブラウザはレスポンスを待たずに次の行のコードに直ちに移動します。つまり、サーバー関数の呼び出しは、想定した順序で実行されない可能性があります。2
つの関数呼び出しを同時に行う場合、どちらの関数が最初に実行されるかはわかりません。ページを読み込むたびに結果が異なる可能性があります。このような状況では、
成功ハンドラと失敗ハンドラ
を使用してコードのフローを制御します。
google.script.run API では、サーバー関数への同時呼び出しは 10 回まで可能です。10
個の呼び出しが実行されているときに 11 回目の呼び出しを行うと、10 個のスポットのいずれかが解放されるまでサーバー関数が遅延します。実際には、この制限について考える必要はほとんどありません。ほとんどのブラウザでは、同じサーバーへの同時リクエストの数がすでに
10 未満に制限されているためです。
たとえば、Firefox では 6
です。同様に、ほとんどのブラウザでは、既存のリクエストのいずれかが完了するまで、超過したサーバー リクエストが遅延します。
パラメータと戻り値
クライアントからパラメータを使用してサーバー関数を呼び出します。同様に、a サーバー関数は成功ハンドラに渡されるパラメータとして値をクライアントに返すことができます。
有効なパラメータと戻り値は、Number、Boolean、String、null などの JavaScript
プリミティブと、プリミティブ、オブジェクト、配列で構成される JavaScript オブジェクトと配列です。ページ内の form
要素もパラメータとして有効ですが、関数の唯一のパラメータである必要があり、戻り値としては有効ではありません。Date、Function、form
以外の DOM 要素、またはオブジェクトや配列内の禁止されている型を含む、禁止されている型を渡そうとすると、リクエストは失敗します。循環参照を作成するオブジェクトも失敗し、配列内の未定義のフィールドは
null になります。
サーバーに渡されるオブジェクトは元のオブジェクトのコピーになります。サーバー関数がオブジェクトを受け取り、そのプロパティを変更しても、クライアントのプロパティには影響しません。
成功ハンドラ
google.script.run
の呼び出しは非同期であるため、クライアントサイドのコードはレスポンスを待たずに次の行に進みます。サーバーが応答したときに実行されるコールバック
関数を指定するには、
withSuccessHandler(function)を使用します。
サーバー関数が値を返すと、API はその値をパラメータとしてコールバック関数に渡します。
次の例では、サーバーが応答するとブラウザのアラートが表示されます。このコードサンプルでは、サーバーサイド関数が Gmail
アカウントにアクセスするため、承認が必要です。スクリプトを承認するには、ページを読み込む前に、スクリプト エディタから
getUnreadEmails 関数を手動で 1 回実行します。または、ウェブアプリを
デプロイして
「ウェブアプリにアクセスするユーザー」として実行すると、アプリの読み込み時に
承認を求められます。
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>失敗ハンドラ
サーバーが応答しない場合やエラーをスローする場合は、
withFailureHandler(function)
を使用して、成功ハンドラの代わりに実行する失敗ハンドラを指定できます。エラーが発生すると、API は
Error
オブジェクトを引数として失敗ハンドラに渡します。
デフォルトでは、失敗ハンドラを指定しない場合、失敗は JavaScript コンソールに記録されます。これをオーバーライドするには、withFailureHandler(null)
を呼び出すか、何も行わない失敗ハンドラを指定します。
この例に示すように、失敗ハンドラの構文は成功ハンドラとほぼ同じです。
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>User オブジェクト
サーバーへの複数の呼び出しで同じ成功ハンドラまたは失敗ハンドラを再利用するには、
を呼び出して、ハンドラに 2 番目のパラメータとして渡されるオブジェクトを指定します。withUserObject(object)この「ユーザー オブジェクト」は、
Userクラスと混同しないようにしてください。クライアントがサーバーに接続した
コンテキストに応答できます。ユーザー
オブジェクトはサーバーに送信されないため、サーバー呼び出しのパラメータと戻り値の制限なしに、関数や DOM
要素など、ほとんどのものを指定できます。ユーザー オブジェクトは、new 演算子で構築されたオブジェクトにすることはできません。
この例では、2 つのボタンのいずれかをクリックすると、1 つの成功ハンドラを共有していても、もう一方のボタンは変更されずに、そのボタンがサーバーの値で更新されます。onclick
ハンドラ内では、キーワード this は 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>フォーム
パラメータとして form 要素を使用してサーバー関数を呼び出すと、フォームはフィールド名をキー、フィールド値を値とする単一のオブジェクトになります。値はすべて文字列に変換されます。ファイル入力フィールドの内容を除き、ファイル入力フィールドの内容はBlob オブジェクトになります。
この例では、ページを再読み込みせずに、ファイル入力フィールドを含むフォームを処理します。ファイルを Google ドライブにアップロードし、クライアントサイドのページにファイルの URL
を出力します。onsubmit ハンドラ内では、キーワード this はフォーム自体を指します。ページのすべてのフォームは、読み込み時にデフォルトの送信アクションが
preventFormSubmit
によって無効になっていることに注意してください。これにより、例外が発生した場合にページが不正確な URL にリダイレクトされるのを防ぎます。
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>スクリプト ランナー
google.script.run は「スクリプト ランナー」のビルダーと考えることができます。スクリプト
ランナーに成功ハンドラ、失敗ハンドラ、ユーザー オブジェクトを追加しても、既存のランナーは変更されません。代わりに、新しい動作の新しいスクリプト
ランナーが返されます。
withSuccessHandler、withFailureHandler、withUserObject
は、任意の組み合わせと順序で使用できます。また、値がすでに設定されているスクリプト
ランナーで、変更関数を呼び出すこともできます。新しい値は以前の値をオーバーライドします。
この例では、3 つのサーバー呼び出しすべてに共通の失敗ハンドラを設定しますが、2 つの別々の成功ハンドラを設定します。
var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);
myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();
プライベート関数
名前がアンダースコアで終わるサーバー関数はプライベートと見なされます。
これらの関数は google.script
から呼び出すことはできず、その名前がクライアントに送信されることもありません。これらを使用して、サーバーで秘密にしておく必要がある実装の詳細を非表示にできます。google.script は、ライブラリ内の関数や、スクリプトのトップレベルで宣言されていない関数も認識できません。
この例では、関数 getBankBalance はクライアント
コードで使用できます。呼び出さなくても、ソースコードを検査するユーザーはその名前を見つけることができます。ただし、関数
deepSecret_ と obj.objectMethod はクライアントから完全に不可視です。
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>Google Workspace アプリケーションでダイアログのサイズを変更する
Google ドキュメント、Google スプレッドシート、フォームのカスタム ダイアログ ボックスのサイズは、クライアントサイドのコードで
google.script.host メソッド
setWidth(width) または
setHeight(height)を呼び出すことで変更できます。(ダイアログの初期サイズを設定するには、HtmlOutput
メソッド
setWidth(width)
と
setHeight(height)を使用します)。ダイアログのサイズを変更しても、親ウィンドウの中央に再配置されず、
サイドバーのサイズを変更することはできません。
Google Workspace でダイアログとサイドバーを閉じる
HTML サービスを使用して Google ドキュメント、スプレッドシート、フォームに ダイアログまたは
サイドバー を表示する場合、
インターフェースを
window.close を呼び出して閉じることはできません。代わりに、
google.script.host.closeを呼び出す必要があります。
例については、Google Workspace
ユーザー
インターフェースとして HTML を提供するをご覧ください。
Google Workspace でブラウザのフォーカスを移動する
ユーザーのブラウザで、ダイアログまたはサイドバーから
Google ドキュメント、スプレッドシート、フォーム エディタにフォーカスを切り替えるには、
メソッド
google.script.host.editor.focusを呼び出します。
このメソッドは、Document
サービス メソッド Document.setCursor(position)
と
Document.setSelection(range) を組み合わせると特に便利です。