猫とGAS

猫の写真を載せる。ついでに環境構築しないでGASアプリを作る

スプレッドシートをGASで扱う方法をなるべく丁寧に解説する①

GASからスプレッドシートを開く方法は大きく分けて2通りある。
スプレッドシートのIDを指定して直接開く方法
②GASに紐付くスプレッドシートを開く方法
の2通りだ。どちらの方法もSpreadSheetAppという専用のライブラリを利用し、その後の使い方が変わるわけではないが、②のGASに紐付くスプレッドシートを開く場合はGAS自体をスプレッドシートから作っておく必要がある。スプレッドシートに紐付くGASの使い方は過去記事を参照してほしい。 neko-gas.hatenablog.com 一方の①スプレッドシートのIDを指定して直接開く方法は、例えば複数のスプレッドシートを利用する場合には使わざるを得ないが、スプレッドシートのIDが勝手に振られるものの上に桁数が多くて非常にわかりづらい。他の人が読んだ時に一目でどのスプレッドシートを参照しているか分かりづらく、例えばスプレッドシートを削除して作り直した場合はIDが変わってしまうので、メンテナンスが必要になるのも欠点だ。
そのため、やや変則的だがここではGASに紐付くスプレッドシートと同じフォルダにある別のスプレッドシートを、ファイル名を指定して開く方法も紹介しよう。ちなみに、getActiveSpreadsheet()というメソッドもあるがgetActive()と全く同じものだ。ややこしい。

スプレッドシートのIDを指定して直接開く方法

スプレッドシートのIDを指定して直接開く

GASに紐付くスプレッドシートを開く方法

GASに紐付くスプレッドシートを開く

GASに紐付くスプレッドシートと同じフォルダにある別のスプレッドシートを、ファイル名を指定して開く方法

GASに紐付くスプレッドシートと同じフォルダにある別のスプレッドシートを、ファイル名を指定して開く

なるべく丁寧に解説する、というタイトルにしたので取得したスプレッドシートをどう使うかについても解説しておく。上で紹介した方法を利用すると、Spreadsheetオブジェクトというものが取得できる。これは取得したスプレッドシートの情報そのものや、シートを簡単に取得するメソッドなどがまとまっているものだ。
メソッドを呼び出した段階でSpreadsheetオブジェクトが取得できているため、そのままさらにシートの取得をしてもいいし、一度変数に格納してからシートの取得をしてもいい。あんまり変数を作りすぎても登場人物が多すぎる物語のように読みづらくなるが、変数があると再利用できて便利な面もあるので、どの段階で変数化するかはコードを書く人のセンス(好み)が出るところだ。下の図で実行しているシートの取得は全く同じ結果になる。

SpreadSheetApp.getActive()で取得したスプレッドシートは変数に格納しても同じように使える

スプレッドシートが開けたら、次はスプレッドシート上のシートを指定する方法について見ていこう。シートを指定する方法は大きく4通りある。
①シート名を指定して直接開く方法
②現在開かれているシートを取得する方法
スプレッドシート上のシートを順次開く方法
1番利用されるのはシート名を指定して直接開く方法だ。これはとても分かりやすい。一方、現在開かれているシートを取得する方法はどのシートが開かれているかに左右されてしまうため若干分かりづらい。シートが1つしかない場合や、シート上のボタンを押すことで実行されるGASなどのシートが必ず特定できる場合以外は使用を避けた方がいいだろう。ちなみに、SpreadsheetApp.getActiveSheet()とするとGASに紐付くスプレッドシートのActiveなシートがいきなり取得できるのだが、SpreadsheetApp.getActive()、SpreadsheetApp.getActiveSpreadsheet()と記述が似ていてとてもややこしい。
最後のスプレッドシート上のシートを順次開く方法は実用的だ。シート数が特定できないけど全部処理する場合や、「2024年XX月」というシートを全て処理する、というような場合に多用することになるだろう。①と②の方法ではSheetオブジェクトというものが取れるが、③は複数取得できるメソッドのため、例え1シートしかなくても配列という複数のオブジェクトがまとまった形式で取得される点には注意が必要だ。

シート名を指定して直接開く方法

シート名を指定して直接開く

現在開かれているシートを取得する方法

現在開かれているシートを取得する

スプレッドシート上のシートを順次開く方法

スプレッドシート上のシートを順次開く

配列の処理の仕方について、配列には配列を操作するメソッドが用意されているため、それを用いて簡単に説明する。アロー関数という書き方を用いているが、JavaScriptは同じ処理でも複数の書き方ができる。その他の書き方については、過去の記事で紹介しているため参考にしてもらいたい。 neko-gas.hatenablog.com 下の図の例では、取得した全てのシートに対してgetName()でシート名を取得し、ログ出力している。

取得した全てのシートに対してgetName()でシート名を取得し、ログ出力

全てのシートのシート名を順次ログ出力する処理

シートが取得できたら次は値の取得だ、といきたくなるが、GASでは値を取得する前にどのセルの値を取得するか、セル範囲を取得する必要がある。セル範囲の取得方法は大きく3種類ある。
①値の入っている全ての範囲を取得する方法
②行数と列数を指定して取得する方法
③セル名を指定して取得する方法
単一の表が入っているようなシートの場合、①で全ての範囲を取得しておけば問題ない。行が増えても列が増えても全て取得してくれるので、とても分かりやすく便利だ。複数の表が混在していたり、そもそも表形式でないような場合には②の方法をお勧めする。汎用性と自由度が高く、行数が増えても対応する方法が取れる。③の方法でも可能だが、列の指定方法がABCになっていて自由度が利かないため、特定の1セルを取得する場合でもない限りあまりお勧めはしない。

値の入っている全ての範囲を取得する方法

値の入っている全ての範囲を取得する方法

行数と列数を指定して取得する方法

getRange関数の最初の引数2つでセルを指定し、後の引数で行数、列数を指定する

セル名を指定して取得する方法

getRange関数にセル名を指定する

椅子と戯れるわたじい

GASでメール一斉送信を自動化する(送り先ごとに本文を編集して添付ファイルまでつけちゃう)

まずはメール本文を編集して使いまわせるようにスプレッドシートで作ってみる。デザインのないシンプルなものにするが、送り先ごとに名前や項目は変えたいので、後で作る一覧から持って来れるようにする。可変の項目の表し方はなんでもいいが、今回は{{}}で括った項目名を置換するようにしよう。タイトルも同じスプレッドシートで管理できると便利なので、1行目をタイトルにすることにする。

1行目はメールタイトル、送信先ごとに変更したい箇所は{{項目名}}にする

メール本文ができたら宛先をリスト化する。ccで自分に送ったりできるようにし、添付ファイルも付けられたら便利だ。スプレッドシートにファイルをそのまま貼り付けるわけにはいかないので、スプレッドシートと同じGoogleドライブに格納されたファイルのタイトルを記載しておく。メール文の項目名も一覧に載せたら完成だ。

項目名をメール文と合わせて一覧を作る

GASでは変数名に日本語を使えるので、今回はコメントがわりに変数名を設定してみたが読みづらいだろうか。
送信先一覧シートのデータを送信先として順次処理していくが、スプレッドシートから取得したままの二次元配列では使いづらいのでJSON形式の配列に整形する。整形は行ごとに行うが、プロパティを作成する場合は項目名ごとに処理したいので、脇に避けておいた先頭行ごとに処理し、列番号で値を取ってきて格納していく。
メール文は2列目にしか必要な情報がないので2列目のみを取得する。メール文の行ごとに、項目名を順次置換していくが、Object.keys(送信先情報)で項目名を取得するのは冗長な感じがしたので送信先一覧の先頭行ごとに置換する形とした。もっと長いコードになるとバグの元になるのでObject.keysで項目名をとる方が賢明かもしれない。
メール文は配列形式になっているため結合する必要があるが、改行コードで結合することを忘れないようにしたい。メールの送信処理そのものはライブラリがあるので簡単だ。引数に送信先アドレス、タイトル、本文を指定するだけで送信できる。それ以外の項目はオプションになる。

送信先一覧の送信先ごとにメール文を置換してメールを送信

ccや添付ファイルはオプションとしてJSON形式で指定できる。他にも送信名や返信先、bccもオプションで指定できるのでカスタマイズが必要な場合は公式ドキュメントを参照してほしい。ccも添付ファイルもオプションなので、送信先一覧シートから列が削除されている場合でもエラーにならないように存在チェックをしておく。添付ファイルはファイル名を指定する形にしたので、スプレッドシートのフォルダを指定して同じ階層に格納されているファイルを対象にする形とした。添付ファイルが多くなる場合には専用の子フォルダを作り、その中を検索しにいく改修が必要となる。添付ファイルはBlobで指定する必要がある。参照可能なスプレッドシートGoogleドキュメントであれば、添付ファイルとするより本文にURLを載せる方が軽くていいだろう。

{ cc:アドレス, attachments:blob }の形式でオプションを作る

キリッとした表情で何かを訴えるわたじい

コード.gs

VueJSで3桁カンマ付き入力項目を作る

See the Pen 3桁カンマ付き入力項目 on CodePen.

入力中かどうかは、input項目にフォーカスが当たっているかどうかで判断をする。フォーカスを当てた時、フォーカスを外した時にそれぞれ呼び出せるイベントがあるので、イベントの中で入力項目の見た目を変更する。カンマをつけてしまうと文字列になってしまうので、バインドする変数はダミーの文字列にしておく。
カンマは正規表現での置換でつける。3つ並びの数値を取り出してカンマをつけたものに置換する、という内容だ。

フォーカスした時にカンマを削除し、フォーカスを外した時にカンマをつける

@inputで入力した時のイベントを定義できる。e.target.valueで入力値を取得できるので、何か文字が入力されるたびに数値の変数に入力値を書き戻している。この際、全角数値は半角に変換し、数値以外の入力は無視するようにしている。最後にダミー項目に値を設定しているが、一度数値にしてから文字列に変換しているのは、先頭に0が入った場合を考慮している。
数値以外が入ってきた時にダミー項目をそのままにしているが、フォーカスを外した時に数値項目からダミー項目の値が設定されるため、その時に見た目は補正される。

e.target.valueで取得した入力値を、全角や数値以外の考慮をしつつ設定する

このままでは一度テキストを選択してフォーカスを外すとカンマがつくが、初期表示ではカンマが付かないままになってしまう。そこで、最初の一回だけ呼び出される処理の中でフォーカスを外す処理を加える。mountedメソッドはアプリのマウント時に呼ばれるため、ここに書くのが適しているだろう。blur()だけ実施しても@blurイベントは発火しないため、blur()の前にfocus()を呼び出しておく必要がある。

フォーカスを外すことでフォーマットを実施

リボンをつけてちょっと高級感を漂わせるわたじい

実は今回のコードには汎用性がない。金額の項目が複数あった場合、メソッドの使い回しはできるだろうが、ダミーの値をどうするかなど冗長になりそうな点が多い。別記事で紹介しているcomponent化を使うのが1番いいのだが、説明の重複が嫌だったので今回はこのままで公開する事とした。component化したコードについては、そのうち別で公開しようと思う。 neko-gas.hatenablog.com

無題.html

css.html

コード.gs

PC、タブレットからGASを使ってGoogleドライブに署名を保存する

See the Pen 署名 on CodePen.

署名欄にはcanvasタグを使用する。画像を表示したり図形を描画したりいろいろな使い方ができるタグだが、そのうちの線を引く機能を活用してマウスがクリックされている間だけ線が引かれるようにする。試してみるとなめらかな線が引かれるが、実際はマウスが動くたびに細かい直線を積み重ねている。canvasタグを使う前の下準備として、Vueのマウント時にキャンバスや線の設定がいる。背景の塗りつぶしはなくても動くように見えるが、画像の保存時に真っ黒い画像が保存されてしまうため注意が必要だ。

画面の設定、線の設定をし、canvasのマウスイベントに線を引くロジックを紐付け

css

クリア処理としては背景を白く塗りつぶすだけだ。保存ボタンはBooleanのisWriteSignを用意して、署名の状況に応じて活性制御を行う。mouseMoveメソッドでtrueにする処理を追加し、クリア処理でfalaseにする。また、この段階では保存ボタンの処理はクリアと同じにしてある。

クリアボタンでキャンバスを白く塗りつつ、isWriteSignで保存ボタンの活性状態を制御する

マウスイベントのみを定義しているため、タブレットスマホで開いた場合何も描かれない。そのためタッチイベントにも処理を紐づけていくが、タッチイベントの場合、位置情報の取得方法がマウスと異なるため、別メソッドを定義する必要がある。しかもタッチイベント時の位置情報は画面全体から見た絶対的な位置になるため、キャンバスの開始点を考慮する必要があり少々複雑になる。

タッチイベントでは絶対的な位置になるため、キャンバスの開始点を考慮する必要がある
タッチイベント用の呼び出しを追加

画面のサイズ変更に対応するために、windowのresizeイベントにキャンバスのサイズ変更を登録する必要がある。ただし、単純にサイズだけを変更してしまうと描き途中の署名が消えてしまうため、署名状態を保持してコピーする必要がある。

元の署名を残すため、サイズ変更後に一時保存した署名を書き戻す

methodsに保存処理を追加し、キャンバスをjpegとして取得、gasサーバへの受け渡しまでを実装する。gasサーバではこれをファイルにするのだが、キャンバスから取得できるデータ形式base64形式なので一度byteデータへの変換を挟む必要がある。そのままで呼び出せるUtilitiesに変換処理があるが、ヘッダ情報が入ったままでは変換ができないため、sliceでこれを削除した上で変換する。Googleドライブへの保存する際は保存先のIDを埋め込む形式をとっているため、xxx...は実際のフォルダIDに差し替える必要がある。htmlからVueJS上の保存処理の呼び出しは、すでに作ってある保存ボタンの@clickを差し替えるだけだ。

キャンバスをjpegデータを作成し、gas側(.gsファイル)でGoogleドライブに保存する


無防備なお腹を曝け出すわたじい

最後に全体サンプルだが、これまでのソースだと保存処理中であることが分かりづらかったり保存フォルダの取得がベタ書きになっていたりするため、4箇所手を加えている。①サーバ処理中に背景をグレーアウトさせるように追加。②名前の入力欄を設け、保存するファイル名に使用。③スプレッドシートと同じフォルダ階層に署名画像を保存するように変更。④スプレッドシートに署名履歴を残すように変更。
保存フォルダの取得処理とスプレッドシートに履歴を残す処理はfunctionを切り分けたため、必要に応じてfunctionの中身を変更すると良いだろう。また、スプレッドシートが紐づいているGASで動くものになっているため、スプレッドシートからファイルを作成して欲しい。スプレッドシートからファイルを作成する手順は過去の記事で紹介している。 neko-gas.hatenablog.com ただ、これでもまだ実用的とは言い難い。通常署名画像だけ保存することはなく、契約書や同意書などの確認対象書類と合わせて保存するものだからだ。署名画像を確認対象と一緒に保存する方法については、ここで触れると長くなりすぎるため、ゆくゆく紹介しようと思う。

無題.html

css.html

コード.gs

GASとVueJSの準備をしよう

GASはEXCELで言うところのVBAEXCELマクロ)のような物だが、スプレッドシートのない単独のスクリプトファイルとしても作成できる。単独で作成すると、Googleドライブ上に青いアイコンのスクリプトファイルが作成される。やり方はとても簡単なのでgifで紹介する。

Googleドライブから直接GASを作成する

拡張機能メニューからAppScriptを選択して作成する。ドキュメントやスライドでも同じ手順で作成できる。このメニューからGASを作成するとGoogleドライブ上にはスクリプトファイルは配置されない。保存したものを再び編集したい場合は、マクロと同じようにスプレッドシートから開く必要がある。スプレッドシートと紐付けるメリットとしては、スクリプト上からIDを指定しなくてもSpreadSheetAppライブラリのgetActive()を呼び出せば紐づくスプレッドシートを取得できるようになる点がある。

スプレッドシートからGASを作成する

スプレッドシートと紐づけるとgetActive()でスプレッドシートを取得できて便利

フォームからGASを作成する場合は若干手順が異なり、3点リーダーのメニューからスクリプトエディタを選択する。フォームとGASを紐づけておくと、回答を受け付けるたびにGASで処理をする、と言うようなことができて便利。

フォームからGASを作成する

CDNというウェブコンテンツ配信サービスを利用する。サービスを利用するといっても何かに登録する必要はなく、VueJSライブラリへのリンクをHTMLに貼り付けるイメージで利用できるのでとっても簡単。邪魔にならないようにhtml終了タグの手前にでも貼るといい。

htmlタグ内にscriptタグでリンクを貼るだけで使える

みずから撫でられに行くわたじい

郵便番号から住所を検索する(複数の住所がヒットする郵便番号対応)

See the Pen 郵便番号検索 on CodePen.

日本郵便がzipcloudという郵便番号検索APIを公開しているため、検索自体は郵便番号をパラメータにセットしてfetchで呼び出すだけで実現できる。fetchにつきもののasync,await構文については、他の記事で簡単に触れているためそちらを見てみてほしい。 neko-gas.hatenablog.com

郵便番号検索APIをfetchで呼び出して住所を取得

郵便番号にひもづく住所が一つなら問題ないが、中には複数の住所がヒットする郵便番号もある。例えば、「029-4205」という郵便番号を検索すると2024年4月の執筆時点で20の住所がヒットする。こういう場合に対応できるよう、VueJSで住所の選択ポップアップを作ってみる。ポップアップの使い方については過去の記事を参考にしてほしい。VueJSでは候補を格納する配列としてcantidates、ポップアップの表示制御をするBooleanとしてshowCandidates、結果の住所を格納する文字列としてaddressを定義している。 neko-gas.hatenablog.com

取得した候補をポップアップの中で一覧表示させる

今回は検索ボックスもおしゃれにしてるし、候補を選択する部分も若干工夫している。cssでどう実現しているか解説しておく。

検索ボックスをおしゃれにして候補一覧のラジオボタンを選択リストっぽくする

わたじいは窓から外を眺めるのが大好きで、尻尾だけでもその可愛さは十二分に伝わってくる。向かいの家の住所でも眺めているのだろうか。いや、そんなはずはない。外を眺めているようで実はこの日は雨戸が閉まっており、何も見えていないはずなのだから。。。

窓から外を眺めるわたじい

全体サンプル

コード.gs

無題.html

css.html

GASでVueJSのcomponentを使う

See the Pen ポップアップを開くComponent on CodePen.

VueJSにはcomponentという非常に便利な機能があり、これを使うと機能を部品として切り出し再利用が可能になる上、ファイルを分けられるので可読性も上がる。componentを使う際は.vueファイルに定義したcomponentをexportし、使う側でimportするのが一般的であり、VueJSの書き方を調べるとこの書き方は非常によく目にする。しかしだ、GASの標準エディタはJavaScriptを記述する.gsファイルと.htmlファイル、それと例外的に.jsonファイルを作成することがしかできない。.vueファイルは作成できず、どんなに便利なcomponentを発見しても同じ書き方で実現することはできないのだ。ここではGASの標準エディタでcomponentの利用を可能にするまでの軌跡を、その奮闘の過程を、ドキュメンタリーに見ていただこう。いや嘘だ。長くなるので結果だけお伝えしたい。

以前作ったポップアップをcomponentを使った書き方に変更する。"templateタグでcomponent化したいHTMLを構築し、defineComponentでidを指定してcomponentを定義する。定義したcomponentはpopup変数に格納する。以前の記事は以下を参照。 neko-gas.hatenablog.com

templateタグを指定してcomponent化する

通常はimportしたcomponentを登録するが、importができないので代わりに変数に格納したcomponentを登録する。呼び出し側はたったこれだけで済んでしまう。

タグ名とdefineComponentの結果を格納した変数を指定してcomponentを登録する

componentを使ってお手軽に呼び出せるようになったが、今のままでは「はい」を押しても「いいえ」を押しても閉じるだけの無意味なポップアップを表示するだけの使い道のないcomponentになってしまう。slotを使ってポップアップの中身は呼び出し元で自由に定義できるようにしよう。

pop-upタグで囲まれた部分がslot部分に置換される

選択かごの中でcomponentと化したわたじい

componentを記述したファイルは.vueファイルのように、cssも含めて一つのhtmlファイルにまとめることができる。ただしimport文での変数名変更ができないため、変数名の同じcomponentは利用できない点、後から読んで変数がどこから来ているか分かりづらい点、呼び出し元のhtml内でスクリプトレットを用いたhtmlの呼び出しが必要になる点などを注意してほしい。

コード.gs

無題.html

ポップアップcomponent.html