Google Apps Script 実践メモ（Form Submit）

先日、仕事で必要に迫られ、Googleフォームからスプレッドシート周りをごにょごにょGoogle Apps Scriptで開発しました。
基本的にはExcel VBAと同じようなものなのですが、パフォーマンスを出すための工夫や、なんだかよくわからないけどクリアしてきた問題などを忘れないうちにメモしようと思います。
（まずはForm Submitから。[SpreadSheet](http://qiita.com/nurburg/items/744ec53477f4ae328555)、Driveと追加していきます）

# フォーム
## Submit時（送信ボタン押した時）に何か処理をしたい
やりたかったのは、Googleフォームをみんなに展開して、スプレッドシートの回答シートにレコードが入って来る度に、そのレコードに対して処理をする、ということです。（処理の過程で気づいたことも今後いろいろ追記していく予定です）
### まずはトリガとイベントを知る
トリガは大きく2種類に分類されていて、まず[Simple Triggers](https://developers.google.com/apps-script/guides/triggers/)は、ドキュメントを開いた時や編集した時といった基本的なトリガとして用意されていて、使用する際の関数名も決まっています。
例えば、onOpen()はドキュメントを開いた時、onEdit(e)は編集したときに使用します。（"e"については後述します）

もう一つは、[Installable Triggers](https://developers.google.com/apps-script/guides/triggers/installable)といって、自分で定義した関数（function）に対してあらかじめ用意されているイベントの中から目的にあったものを割り当ててトリガを設定します。
下のキャプチャの例では、独自に作成したmyfunctionを時間主導型にして10分単位で起動し、myfunction2をスプレッドシートの編集時に起動する設定にしています。
![トリガとイベントの設定](https://qiita-image-store.s3.amazonaws.com/0/49702/21cc9a09-f15e-5fbc-aa32-b9df46665646.png)

### Event Objectsについて
前述したonEdit(e)の"e"の部分についてです。
[Event Objects]:https://developers.google.com/apps-script/guides/triggers/events
[Event Objects][Event Objects]のドキュメントにもあるように、トリガが呼ばれる元となるイベントにおいて、そのイベントの発生内容を引数として取ることができます。（別に"e"でなくてもよいのですが、公式ドキュメントで使われている表記を踏襲します）
変更されたセル（Range）の情報を取るにはこんな風に書きます。

```js
function onEdit(e){
  var range = e.range;        //イベントオブジェクト"e"からセルの情報を取得
  Logger.log(range.getRow()); //例えばセルの行番号をLogger.log()でログに出力
}
```

>念のため書きますが、当然、どのシートのどのセルを編集しても動くので、実際にはセルが存在しているシート名（range.getSheet().getSheetName()）や行番号や列番号（range.getColumn()）など目的に応じてIF文等で縛ってから処理を書いてください。

### フォームSubmitイベントを使用する
で、今回はフォームのSubmit時に処理したいので、ドキュメント[Event Objects][Event Objects]に書いてある「Form submit(installable)」というものに該当するのですが、実は、フォーム自体に処理するものと、スプレッドシートに処理するものと2種類ありまして、それぞれで微妙に異なるので間違わないようにする必要があります。
onEdit()だけでなく、Form Submitでもe.rangeで回答シートに更新された（転記された）レコードのセルの情報を取得できますし、フォームに入力させた値を連想配列で取得することもできます。
実装したい内容にもよりますが、回答シートに更新されたレコードを使って、かつその行に対して処理をしたかったので以下のような書き方をしました。

```js

function onFormSubmit(e){
  var range = e.range;

  //例えばこんな処理
  range.setVerticalAlignment("top");                   //挿入されたセルを全て上揃えにする
  range.getRange(range.getRow(),5).setValue("hoge");  //挿入行のE列のセルに"hoge"を入力

}
```

また、トリガは次のように設定します。
![フォーム送信時のトリガ設定](https://qiita-image-store.s3.amazonaws.com/0/49702/750e8758-4b8d-8c57-04af-65c2f8c525ca.png)

## その他あれやこれや
どうやら、Submitで回答シートに入ってきたレコードによる変更って、Simple TriggersのonEdit()で拾えないみたいです。明示的にそのことに言及されているドキュメントを探せなかったのですが、システムによって挿入されたレコードは、"Edit"ではないという仕様なんですね、きっと。それがあってForm Submitを使いました。

あと、Simple TriggersのonEdit()と、Installableの方にも「編集時」ってのがあってそれらは何が違うのか、って気がしますが、Installableの方は常にトリガを登録したユーザによる実行になってしまいます。例えばメールを送信する処理を記述した場合、送信者は常にトリガを登録したユーザアカウントになります。<br>ということで、Installableの場合は初回の実行時に実行許可を求めるダイアログが出てきますので、実行を許可してください。

で、最初は自分もよくわかってなくて、function onEdit(e){}を記述した上で、さらにonEdit()に編集時のトリガを設定する必要があるのかと思って、二重に編集時のトリガを設定してしまい、うまく動かなくなったりしました。

# このシリーズの続き
## スプレッドシート
[こちら](http://qiita.com/nurburg/items/744ec53477f4ae328555)にまとめました。
* シートの内容を処理する方法（getSheetValues()で配列[][]に取得したほうが、API1回で済むので処理が早い、とか）
* 別のシートをURLとかから呼び出して、そこに書き込む方法（SpreadsheetApp.~とDriveApp.~とがあって実は後者でしか呼べないメソッドもあったり）

## Googleドライブ
* Driveのフォルダやファイルへの権限の付け外し（Google Driveならでは発想が必要です）
* Driveの子フォルダをループさせながら何かしら処理する方法（folder.hasNext()あたりのCollectionの処理でハマったこと）

## Apps Script
* 多次元配列や連想配列を使った時の処理（これはJavaScriptそのものでもあったりするのでApps Scriptの話じゃないですが）