今まで、Google Apps Script(以後、GAS)で他のWebサービスと連携したり、OCRで画像から文字列を取得してみた。
Google Apps ScriptのHTML ServiceでGoogle Calendarの予定を取得してみる
Google Apps ScriptでJPEGの画像からOCRで画像内の文字列を取得してみた
あと、Webアプリ開発として把握しておきたいことと言えば、
ファイルのアップロード等を行うためのフォームだろう。
というわけでマニュアルを読んでみた。
HTML Service: Communicate with Server Functions | Apps Script | Google Developers Forms
コードを確認する限り、
GASのHTML Serviceでは、他の言語にあるようなPOSTの同期ではなく、
非同期で書かなければいけないらしい。
というわけで
とりあえずサンプルコードを試す。
Googleドライブ内でスクリプトエディタを開き、下記のコードをコピペして保存する。
コード.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>
コード.gsとindex.htmlの関係は下記の記事に記載してある。
Google Apps ScriptのHTML Serviceを試してみた
コードの詳細を見る前にサンプルコードを実行してみる。
ウェブアプリケーションとして導入してみると
HTMLのBodyの箇所で記述したアップロードフォームと実行ボタンが表示されている。
ファイルを選択してボタンを押してみると、
しばし待ったところで、Got it!というリンクが表示される。
このリンクをクリックすると、
アップロードした画像の詳細画面が表示される。
Googleドライブのマイドライブ内に画像がアップロードされるようだ。
一通り動作を確認したので、コードの確認に移る。
コード.gs内で記載した
function processForm(formObject) { var formBlob = formObject.myFile; var driveFile = DriveApp.createFile(formBlob); return driveFile.getUrl(); }
はHTML側からの非同期で送信されたファイルのデータをGoogleドライブ内にアップロードして、
アップロードした先のファイルのURLを返す関数になっているようだ。
processForm関数はコード.gsのdoGet関数内では実行されていないので、HTML側での実行になる。
続いて、
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>
HTML側のコードを見てみる。
preventFormSubmit関数はHTML表示の際に実行されるコードなので、今回は触れないでおく。
今回注目したいのはformタグ内のsubmitイベントで指定されているhandleFormSubmit関数の方で、
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>'; }
google.script.run.withSuccessHandler(関数名).[コード.gsで作成した関数]
というコードが書かれている。
GASのHTML Serviceでコード.gs側で記述した関数の呼び出し方はいくつかあるけれども、
HTML側のscriptタグ内でgoogle.script.run.[コード.gsで作成した関数]のように記述することで呼び出すことも可能で、
コード.gsで作成した関数の実行の後に他のイベントを実行させたい場合は、
google.script.run.withSuccessHandler(関数名).[コード.gsで作成した関数]
このようにコード.gsで実行したい関数より前にチェーンメソッドの形式でwithSuccessHandler(HTML側の関数名)を指定すれば良く、
コード.gs側の関数の実行で成功した場合は、
google.script.run.withSuccessHandler(関数名).[コード.gsで作成した関数]
で
失敗した場合は、
google.script.run.withFailureHandler(関数名).[コード.gsで作成した関数]
で、
成功と失敗の両方を登録しておきたい場合は、
google.script.run.withSuccessHandler(関数名).withFailureHandler(関数名).[コード.gsで作成した関数]
このように繋げれば良いらしい。
JavaScriptにあるPromiseの要領で使用すれば良いはず。
継承とプロトタイプチェーン - JavaScript | MDN
withSuccessHandler関数の引数で指定した関数の引数、
つまりはfunction updateUrl(url)のurlはコード.gsで作成したprocessForm関数の返り値を受け取ることになっている。
今回のフォームのアップロードと、
前回のGoogleドキュメントでのOCRを組み合わせれば、
HTML Service内で画像ファイルをアップロードして、同一画面上で画像内の文字列を出力するWebアプリが作れるようになるはず。