【0からGASを学ぶ】GASを用いてGoogleフォームの各項目を取得しよう

# はじめに
本シリーズでは、GASの始め方や便利な使い方、ビジネス活用まで幅広く解説します。シリーズをひと通り読んでいただければ、あなたもきっとGASマスターになれるはずです。

# シリーズの対象者
* そもそもGASってなんだか**わからない**方
* GASを学びたいけど**何から始めればいいか**わからない方
* GASはわかり始めたけど、**もっと活用ができないか**と模索している方
* とにかく**Googleが好き！** という方

# 前回記事
https://qiita.com/gas-suke/items/cf4a809d54464a43f3ac

# Googleフォームと連携する
では早速始めていきましょう。【0からGASを学ぶ】シリーズの第11回は「GASを用いてGoogleフォームの各項目を取得しよう」です。前回からGoogleフォームとGASの連携をはじめましたので、今回は今後の活用のために各フォーム項目値の取得方法をお伝えしていこうと思います。

## 今回やること
1. Googleフォームのフォーム項目をGASで取得する。
1. 回答内容をGASで取得して、console.logに出力する。

:::note info
やることは**単純**ですが、項目種別によっては**少々特殊な取得方法となります**ので、参考にしていただければ幸いです。
:::

## 事前準備
### Googleフォームを作成
今回の起動元となるフォームを作成していきましょう。項目種別を**すべて網羅**させるため以下の項目を盛り込んでください。
1. 記述式
1. 段落
1. ラジオボタン
1. チェックボックス
1. プルダウン
1. ファイルのアップロード
1. 均等目盛
1. 選択式_グリッド
1. チェックボックス_グリッド
1. 日付
1. 時刻

参考に私が作成したフォームは以下となります。

https://forms.gle/jTK7s1sah5RFK11u7

### 試しに一度回答
Googleフォームを作成したら、右上の「プレビュー」ボタンを押下して、一度回答してみましょう。のちほど**回答データを取得するためだけ**なので、どのような回答でも構いません。

## プログラム開始
### GASエディタを開く
準備したGoogleフォームから**コンテナバインド型でGASプログラム**を記述していきましょう。Googleフォームからコンテナバインド型のGASを開く場合は、<a href="https://qiita.com/gas-suke/items/cf4a809d54464a43f3ac#gas%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF%E3%82%92%E9%96%8B%E3%81%8F" target="_blank">こちら</a>を参考にしてください。では、どんどんいきますよ、ついてきてください。

### STEP.1　Googleフォームのフォーム項目をGASで取得する
```javascript:Qiita011.gs
function Qiita011_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }
  console.log(itemResponses);
}
```


```:実行結果
12:05:13	お知らせ	実行開始
12:05:14	情報	[ { toString: [Function],
    getFeedback: [Function],
    getItem: [Function],
    setScore: [Function],
    setFeedback: [Function],
    getScore: [Function],
    getResponse: [Function] },
…
  { toString: [Function],
    getFeedback: [Function],
    getItem: [Function],
    setScore: [Function],
    setFeedback: [Function],
    getScore: [Function],
    getResponse: [Function] } ]
12:05:14	お知らせ	実行完了
```
これだとどんな値がとれているかはわかりませんが、ばっちりとオブジェクトは取得できていますので準備万端です。

:::note info
前回は、以下のような感じに三項演算子で記載をしましたが、
```javascript
  const itemResponses = (e !== undefined)
                        ? e.response.getItemResponses()
                        : FormApp.getActiveForm().getResponses()[FormApp.getActiveForm().getResponses().length-1].getItemResponses();
```
記事を見ていただいてる方から、こうした方が**API呼び出しの回数を減らせるのでは**とアドバイスいただきました。**ちりつも**はGASにおいて大事な要素なので、ありがたいご指摘です。プログラムは**ステップ数が少ないほうがいい！** という方もいらっしゃると思いますが、私はこちらを採用します。
:::

### STEP.2　回答内容をGASで取得して、console.logに出力する
では、回答内容を確認していきましょう。まずは単純にタイトルと回答を取得してみます。
```javascript:Qiita011.gs
function Qiita011_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }
  // 取得したフォーム項目を1件ずつ処理する
  itemResponses.forEach(function(itemResponse){
    console.log('********************');
    console.log(itemResponse.getItem().getTitle());
    console.log(itemResponse.getResponse());
  });
}
```

```:実行結果
12:29:11	お知らせ	実行開始
12:29:12	情報	********************
12:29:12	情報	記述式
12:29:12	情報	記述式の回答です。
12:29:12	情報	********************
12:29:13	情報	段落
12:29:13	情報	段落の回答です。
改行もできるのが特徴です。
12:29:13	情報	********************
12:29:13	情報	ラジオボタン
12:29:13	情報	その他は自由記述ができるので便利です。
12:29:13	情報	********************
12:29:13	情報	チェックボックス
12:29:13	情報	[ '選択肢 2', 'その他は自由記述ができるので便利です。' ]
12:29:13	情報	********************
12:29:13	情報	プルダウン
12:29:13	情報	選択肢 2
12:29:13	情報	********************
12:29:13	情報	ファイルのアップロード
12:29:13	情報	[ '14hA8OJAK3pVLB7HVjA3pI5SzJRqBjI6F' ]
12:29:13	情報	********************
12:29:13	情報	均等目盛
12:29:13	情報	2
12:29:13	情報	********************
12:29:13	情報	選択式_グリッド
12:29:13	情報	[ '列 2', '列 1' ]
12:29:13	情報	********************
12:29:13	情報	チェックボックス_グリッド
12:29:13	情報	[ [ '列 2' ], null ]
12:29:13	情報	********************
12:29:13	情報	日付
12:29:13	情報	2023-11-16
12:29:13	情報	********************
12:29:14	情報	時刻
12:29:14	情報	22:51
12:29:14	お知らせ	実行完了
```
実行結果を見ると、`getResponse()`により、択一のものに関しては回答がそのまま、選択式のものに関しては配列で取得できていることがわかります。
では、これを考慮して、各項目タイプにより回答の取得方法を変化させましょう。
```javascript:Qiita011.gs
function Qiita011_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }
  itemResponses.forEach(function(itemResponse){
    switch (itemResponse.getItem().getType()) {
      case FormApp.ItemType.TEXT:             // 記述式
      case FormApp.ItemType.PARAGRAPH_TEXT:   // 段落
      case FormApp.ItemType.MULTIPLE_CHOICE:  // ラジオボタン
      case FormApp.ItemType.LIST:             // プルダウン
      case FormApp.ItemType.SCALE:            // 均等目盛
      case FormApp.ItemType.DATE:             // 日付
      case FormApp.ItemType.DATETIME:         // 時刻
        console.log(itemResponse.getResponse());
        break;
      case FormApp.ItemType.CHECKBOX:         // チェックボックス
        itemResponse.getResponse().forEach(function(item) {
          console.log(item);
        });
        break;
      case FormApp.ItemType.FILE_UPLOAD:      // ファイルのアップロード
        itemResponse.getResponse().forEach(function(item) {
          const upFile = DriveApp.getFileById(item);
          console.log(upFile);
        });
        break;
      case FormApp.ItemType.GRID:             // 選択式_グリッド
        itemResponse.getResponse().forEach(function(item, idx) {
          if (item) {
            console.log(`${idx+1}行目：${item}`);
          }
        });
        break;
      case FormApp.ItemType.CHECKBOX_GRID:    // チェックボックス_グリッド:
        itemResponse.getResponse().forEach(function(item, idx) {
          if (item) {
            item.forEach(function(choise){
              console.log(`${idx+1}行目：${choise}`);
            })
          }
        });
        break;
      default:
        console.log('タイプが別のものが来た場合')
        break;
    }
  });
}
```
各項目は、`getType()`により**項目タイプの取得が可能**であり、`FormApp.ItemType`で**判別が可能**です。質問項目だけでなく、セクションやタイトルなども取得することが可能です。

https://developers.google.com/apps-script/reference/forms/item-type?hl=ja

`itemResponse.getResponse()`で単純に取得できるものは置いといて、他のタイプを確認していきましょう。

#### FormApp.ItemType.CHECKBOX
チェックボックスは**ラジオボタンとは異なり複数の選択**がされる場合があります。そのため、`itemResponse.getResponse()`で得た回答の配列を`forEach`で取得すると良いかと思います。
```javascript
itemResponse.getResponse().forEach(function(item) {
  console.log(item);
});
```

#### FormApp.ItemType.FILE_UPLOAD
ファイルのアップロードは**アップロードしたファイルのIDを配列で取得**することができます。そのため、チェックボックスと同様に`itemResponse.getResponse()`で得た回答の配列を`forEach`で取得し、得たIDを`DriveApp.getFileById()`により**GAS内で扱いやすく**すると良いかと思います。
```javascript
itemResponse.getResponse().forEach(function(item) {
  const upFile = DriveApp.getFileById(item);
  // これをどう扱うかは、やりたいこと次第。
});
```

#### FormApp.ItemType.CHECKBOX_GRID
選択式グリッドは各行の回答が配列で返ってくるため、`itemResponse.getResponse()`で得た回答の配列を`forEach`で取得すると良いかと思います。
```javascript
itemResponse.getResponse().forEach(function(item, idx) {
  if (item) {
    console.log(`${idx+1}行目：${item}`);
  }
});
```
:::note info
主に「各行で1つの回答を必須にする」オプションを付与して利用することが多いかと思いますが、**上記のように`if (item){…}`で各行の回答がnullかどうかを判別**すれば汎用的に使えます。
:::

#### FormApp.ItemType.CHECKBOX
チェックボックスグリッドは**各行の回答が配列**で、さらに**各行内における回答も`FormApp.ItemType.CHECKBOX`と同様に配列で返ってくる**ため、正確に回答を捕捉するためには`itemResponse.getResponse()`で得た回答の配列を`forEach`で取得し、**さらにそれを`forEach`で取得する**と良いかと思います。
```javascript
itemResponse.getResponse().forEach(function(item, idx) {
  if (item) {
    item.forEach(function(choise){
      console.log(`${idx+1}行目：${choise}`);
    })
  }
});
```
:::note info
選択式とグリッドと同様に「各行で1つの回答を必須にする」オプションを付与することができますので、**上記のように`if (item){…}`で各行の回答がnullかどうかを判別**すれば汎用的に使えます。
:::

### 
# おわりに
お疲れ様でした。
第11回は「GASを用いてGoogleフォームの各項目を取得しよう」ということで、Googleフォームで提供している**テキスト形式やプルダウン形式、マトリクス形式など**にどうアクセスすればよいかお伝えしました。今回はconsole.logに出力するといった非常に単純なことしかしておりませんが、**取得した回答を煮るなり焼くなりすればなんでもできます**。次回は私がとある案件で行った「Googleフォームで欠席フォームを作成し、その回答から欠席届を作成する」をご紹介したいと思います。案件で行っただけあって、**超実践的**ですよ。引き続き、GASを楽しんでいきましょう！！
記事を読んで、「良いな」や「今後に期待できる！」と感じて頂けたら**いいね**や**フォロー**、**コメント**いただけると幸いです。それではまた次回をお楽しみに！

## ブログでより詳しく解説しています！
以下画像をクリックしてブログにアクセス！！
<a href="https://gas-4u.com/gas10/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/09ad4b86-c2af-9e92-d05b-092c244ddc9c.png" width="600"/></a>