【GAS】Googleフォームのチェックボックスの回答をスプレッドシートに反映させて日程調整を簡単にする

# 概要
社内で会議招集や勉強会等をするために、「どの時間になら参加できますか？」と、20人規模に対して口頭やメールでやり取りするのが煩雑だったので、Googleフォームとスプレッドシートを合わせてなんかやりやすく出来ないかなと考えました。
日程的にこの時間でないと無理、とタイトな人が多いため、従来の方法では結構苦慮していたのが要因です。
最初にフォームとスプレッドシートを作ってコードを捩じ込めば、かなり楽出来そうです。

# 完成物
大したものでもないのでまず見てもらうのが早いかと。

1.ユーザーがフォームを送信

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581933/910f8049-e4f6-365e-802d-9b3a6a9a0f9d.png)

2.フォームの送信をトリガーに、スプレッドシートにフォームの内容が転記される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581933/8feec33a-f304-f0f0-199e-d668089ca8dd.png)

フォームの内容を加工できるので、今回のように誰がどの時間帯に参加できるかを表にできます。
全員参加可能な研修などを２～３回に分けて実施する場合などの日程調整には優位。

# スクリプトと記述場所
まずはフォームとスプレッドシートを作成します。
これらを作成後、スクリプトを記述しにいきます。
今回は前項でお見せしたものを例に説明します。

## 記述場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581933/77322c66-9abf-293e-2e50-5ad6330d3e6c.png)

フォーム編集画面右上の縦三点ボタン下にあるスクリプトエディタを開き、Apps Scriptを起動します。
スプレッドシート側からでもApps Scriptを起動できますが、今回はフォーム側から起動した前提でコードを記載します。
詳細は後述しますが、どちらから起動するかによってイベントオブジェクトが少し異なるようです。

## コード

```javascript
function makeSchedule(e) {
  //スプレッドシートID
  let ss_id = '任意のスプレッドシートID';
  const sh = SpreadsheetApp.openById(ss_id).getSheetByName('任意のシート名');

  //Googleフォームの記入結果取得
  const item = e.response.getItemResponses();
  let q1 = item[0].getResponse();
  let q2 = item[1].getResponse();
  let q2_1 = q2[0];
  let q2_2 = q2[1];
  let q2_3 = q2[2];
  let q2_4 = q2[3];

  //シートの最終行を取得
  var sh_last = sh.getLastRow();

  //シートへの記入
  sh.getRange(sh_last+1,1).setValue(q1);
  if(q2_1){
    if(q2_1.indexOf('10:10～11:00')> -1){
      sh.getRange(sh_last+1,2).setValue('○');
    };
    if(q2_1.indexOf('13:30～14:30')> -1){
      sh.getRange(sh_last+1,3).setValue('○');
    };
    if(q2_1.indexOf('15:10～16:00')> -1){
      sh.getRange(sh_last+1,4).setValue('○');
    };
  };
  if(q2_2){
    if(q2_2.indexOf('10:10～11:00')> -1){
      sh.getRange(sh_last+1,5).setValue('○');
    };
    if(q2_2.indexOf('13:30～14:30')> -1){
      sh.getRange(sh_last+1,6).setValue('○');
    };
    if(q2_2.indexOf('15:10～16:00')> -1){
      sh.getRange(sh_last+1,7).setValue('○');
    };
  };
  if(q2_3){
    if(q2_3.indexOf('10:10～11:00')> -1){
      sh.getRange(sh_last+1,8).setValue('○');
    };
    if(q2_3.indexOf('13:30～14:30')> -1){
      sh.getRange(sh_last+1,9).setValue('○');
    };
    if(q2_3.indexOf('15:10～16:00')> -1){
      sh.getRange(sh_last+1,10).setValue('○');
    };
  };
  if(q2_4){
    if(q2_4.indexOf('10:10～11:00')> -1){
      sh.getRange(sh_last+1,11).setValue('○');
    };
    if(q2_4.indexOf('13:30～14:30')> -1){
      sh.getRange(sh_last+1,12).setValue('○');
    };
    if(q2_4.indexOf('15:10～16:00')> -1){
      sh.getRange(sh_last+1,13).setValue('○');
    };
  };
}
```

## 注意点
```javascript
 let q2 = item[1].getResponse();
```
の返り値は本例の場合、下記のように二次元配列になります。
グリッドなので当然っちゃあ当然ですが。
```javascript
[ [ '10:10～11:00', '13:30～14:30' ],
  [ '13:30～14:30' ],
  null,
  [ '10:10～11:00', '13:30～14:30', '15:10～16:00' ] ]
```
そのため、後半のスプレッドシートに転記する箇所で、各回答がnullか否かをきっちり判定してあげる必要があります。
ここをサボってしまうと、予定が合わない日が1日でもある人がいる（nullを含む回答をした人がいる）と、途端にエラーを吐いてしまいます。

# おわりに
初めてのGAS作成でしたが、一番のハマりポイントはイベントオブジェクトの取り扱いでした。
今回、Googleフォーム側からスクリプトの記述を実施しましたが、参考にしたサイトはスプレッドシート側から記述を行っているものでした。
どうも調べてみた限り、フォームを対象にしたイベントオブジェクトとシートを対象にしたイベントオブジェクトでは使用可能なイベントオブジェクトが異なるようです。

https://developers.google.com/apps-script/guides/triggers/events

スプレッドシート側からやる場合、getResponse（response）ではなくnamedValuesを使用してあげる必要があります。
調べた限りではスプレッドシート側から作成する側の方が大多数のような気がします。使えるイベントオブジェクトが多い事から優位性があるのでしょうか。
また、今回のコードではたらたらとifを使ってスプレッドシート側に転記していましたが、もっと良い書き方が出来ないか代案を探したいと思います。