意地でもGoogleフォームで二段階プルダウンを作りたい。【GAS】

# Googleフォームでどうしても二段階プルダウンを作りたかったので作ってみたの話

## とにかく今すぐ二段階プルダウンを作りたい人へ
こちらのスプレッドシートをコピーし、使い方シートに沿ってお使いください！
[2段階プルダウン作成スプレッドシート](https://docs.google.com/spreadsheets/d/1tXEXmBsFud5ZTkvrp2WzORdxgx4-nxJFAWYzeO-hP1U/edit?usp=sharing)

こちらのスプレッドシートから自動でこのような二段階プルダウンを実現したGoogleフォームを作成することができます。
[好きな市区町村アンケート](https://forms.gle/NaKFiWwUAHDNpUeD9)
（よろしければお好きに回答してみてください。）

# 目次
[1.はじめに](#1-はじめに)
[2.完成イメージ](#2-完成イメージ)
[3.実装](#3-実装)
[4.終わりに](#4-終わりに)
[5.参考文献](#5-参考文献)

# 1. はじめに
アンケート等に使われるGoogleフォームは無料で利用することができ、集計も容易にできる便利なソフトウェアです。
回答方法の1つに **プルダウン** があります。
このように指定した選択肢から回答者に選ばせることができます。
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609423/1faec666-396c-d077-dbff-05df0d25e33b.png" width="600">
</div>


### 今回作りたいのは　 **二段階プルダウン**
つまり、 回答者が一段階目のプルダウンで選んだ選択肢によって二段階目のプルダウンを表示させたい　ということです。
例えば、住んでいる市区町村のアンケートを取りたい時に、一段階目のプルダウンで都道府県を選ばせ、
二段階目のプルダウンではその都道府県の市区町村を選択肢として表示させるような仕組みをイメージしています。

# ２．完成イメージ
　Googleフォームは、フォームの最終回答の段階でのみスクリプトを作動させることができるので、
入力状況に応じて選択肢を変化させるということは実現できません。
そこで今回は、 **セクション移動** を自動で作成することにより、二段階プルダウンを無理やり実現させました。
具体的には居住地のアンケートをとりたい時に、以下のようなスプレッドシートから自動で二段階プルダウンを作成することが今回の目標です。
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609423/d90a1e98-9f55-d910-dc21-8a0ad98f28e5.png" width="900">
</div>


二段階プルダウン
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609423/7ad9521b-93ef-7cab-feab-829cba7516ed.png" width="400">
</div>
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609423/5aefdeb3-07ee-01a4-9e44-e75edf5d17d2.png" width="400">
</div>

スプレッドシートから自動で二段階プルダウンを作成した後は、通常通りお好きなアンケートを追加することが可能です。

# ３．実装
今回実装したスプレッドシートがこちらになります。コピーしてお使いください。
[2段階プルダウン作成スプレッドシート](https://docs.google.com/spreadsheets/d/1tXEXmBsFud5ZTkvrp2WzORdxgx4-nxJFAWYzeO-hP1U/edit?usp=sharing)

今回スプレッドシートに紐づけ、GASで作成した関数は主に2つです。
* create_form_sample
スプレッドシートの情報からセクションを作成し、セクション移動情報を追加し、フォームを作成する関数

* onSubmit(e)　　　
回答された項目を整頓して集計するための関数

コードは次の通りです。
```javascript:create_form_sample
//フォーム作成
function create_form_sample(){
  const dataValues = ss.getSheetByName('項目データ').getDataRange().getValues();
  const values = ss.getSheetByName('概要').getDataRange().getValues();
  const formTitle = values[0][1]; //タイトル
  const title_first = values[2][1]
  const title_second = values[3][1]

  const form = FormApp.create(formTitle);

  //セクション1
  const item = form.addListItem()
    .setTitle(title_first)
    .setRequired(true);


//第一プルダウンの選択肢をarr_firstに格納
var arr_first = [];
  for(let i = 0;i < columns_sum; i++){
  arr_first[i] =form.addPageBreakItem().setTitle(dataValues[0][i]);
    form.addListItem()
      .setTitle(title_second)
      .setChoiceValues(generateArray(dataValues, i))
      .setRequired(true);
    
  }

//セクションジャンプ情報と共に第二プルダウンの選択肢をfirsr_choicesに格納
var first_choices = []
  for (let i = 0;i < columns_sum; i++){
    first_choices.push((item.createChoice(dataValues[0][i], arr_first[i])));
  }

item.setChoices(first_choices);

//仮質問にジャンプ
question = form.addPageBreakItem().setTitle(values[1][0]);
question.setGoToPage(FormApp.PageNavigationType.SUBMIT);

for(let i = 0;i < columns_sum; i++){
arr_first[i].setGoToPage(question)
}
}


//第二段階の選択肢を取得
function generateArray(values, column){
  return (values.map(record => record[column]).filter(value => value)).slice(1,);
}

//カラム数を取得
function get_columns(sheet){
  const columns = sheet.getLastColumn();
  return columns;
}
```

フォーム作成関数では、自動でGoogleフォームを作成することができます。
まずセクション１に第一プルダウンの項目を作成し、
セクション２～順に第二プルダウンの項目を作成します。
セクション１の回答次第で、自動で正しいセクションにジャンプし、
第二プルダウン回答後に、仮質問にジャンプするように設定されます。


---
セクションを分けると、Googleフォームにデフォルトである回答集計シートでは、セクションごとに列が生成され、集計しにくい状態になります。

そこで、綺麗に集計データを収集するために、以下の関数を作成しました。
```javascript:onsubmit(e)
function onSubmit(e) {

var timeStamp = e.values[0];
var first_choice = e.values[1];
var sh_name = '回答整理'; //スプレッドシートのシート名を指定
var answer_sh = ss.getSheetByName(sh_name);
var last_row = answer_sh.getLastRow();

for (var i = 2;i <2+columns_sum ; i++){
  if(e.values[i].length > 0){
    var second_choice = e.values[i];
    break;
  }
}

answer_sh.getRange(last_row + 1, 1).setValue(timeStamp);
answer_sh.getRange(last_row + 1, 2).setValue(first_choice);
answer_sh.getRange(last_row + 1, 3).setValue(second_choice);

for(var i = 2+columns_sum; i < e.values.length; i++){
  answer_sh.getRange(last_row + 1, i-columns_sum+2).setValue(e.values[i]);
  Logger.log(e.values[i])
}

}
```
こちらの関数を、 **トリガー設定** することで、整頓された状態で集計データを収集することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609423/2614fa51-f83c-fcb9-4b8f-6096b73c8e03.png)


# ４．終わりに
今回自動でGoogleフォームに二段階プルダウンを作成するシステムを実装しました。
ここまで手がかかるくらいなら記述式にすればいいじゃん。。と思う方もいらっしゃるかもしれませんが、
表記ゆれが許せない人や、膨大な選択肢を作りたい一部の方に役立つことができれば幸いです。

# ５．参考文献
* [Google Forms for Developers Forms API](https://developers.google.com/forms/api)
* [Googleスプレッドシート 完全攻略](https://technical.verybestcbp.com/addformitem/)
* [Google Apps Script からGoogleフォームの回答を送信する](https://qiita.com/nushitoritarou/items/7690c9573b75c6498f2b)