今日は教育のお話ではありません。プログラミング(Google Apps Script, GAS)に関する記事なので、興味のない人はスルーしてくださいね。
ことの始めはGoogleフォームを使った教育のアンケート調査です。「アンケート結果を一般公開したいけど、個人情報は伏せておきたい」と相談を受けました。GASでプログラミングをすれば多分出来るだろうと仕事を引き受けたのですが、これが想定よりも大変で苦労しました。ネットにも全く情報がなかったので、ブログでノウハウを公開したいと思います。
解決プラン
Googleフォームには、アンケートの一部だけを非公開・公開に設定することはできません。そこで考えたのは「投票用のフォーム」と「公開用のフォーム」の2種類を用意しておいて、それをリアルタイム同期させる方法です。公開用のフォームは、個人情報(メールアドレスや名前)を省いておけば、目的達成です。
一番の難所だったのが、2種類のフォームを同期させる方法です。実は「Googleフォームを連携させたスプレッドシートを編集すれば、Googleフォームの回答も変更される」と最初は考えていたのですが、これが大きな勘違いでした。色々と試行錯誤した結果、最終的にGASで「公開用のフォーム」に回答をsubmitするプログラムを作って解決しました。
作業の流れ
作業の流れは以下の通りです。
- 「投票用のフォーム」をコピーして「公開用のフォーム」を作り、設定を調整する
- 「投票用のフォーム」からスクリプトエディタを起動させ、GASでプログラミングを行う
- 「投票用のフォーム」の全ての回答を「公開用のフォーム」にコピーする(動作確認含む)
- 「投票用のフォーム」にトリガーを設定して、投票用の最新の回答が「公開用のフォーム」にコピーされるようにする
1. 「公開用のフォーム」の作成
まずは「投票用のフォーム」をコピーして「公開用のフォーム」を作ります。「公開用フォーム」の設定は以下の通り。
「公開用のフォーム」は公開するためのものなので、質問項目の中で公開したくない情報(個人情報など)があったら、事前に削除しておいてください。また、いたずら防止のためにも「回答の受け付け」はオフにしておきましょう。
2. スクリプトエディタでプログラミング
次に、「投票用のフォーム」からスクリプトエディタを起動させ、GASのプログラミングを行います。プログラミングコードは以下をコピペしてください。(JavaScriptと表示されていますが、言語はGoogle Apps Scriptです。)
// 投票用フォームの情報
const orgId = "abcdefghijklmnopqrstu"; // 要変更
const orgForm = FormApp.openById(orgId);
const orgRes = orgForm.getResponses();
// 公開用フォームの情報
const pubId = "12345678987654321"; // 要変更
const pubForm = FormApp.openById(pubId);
const pubRes = pubForm.getResponses();
// 最新の回答を公開用フォームにコピーする
function copyRecent() {
// 公開用フォームの回答受け付けを開く
pubForm.setAcceptingResponses(true);
// 一番最後(=最新)の回答をコピー
copy(orgRes[orgRes.length - 1])
// 公開用フォームの回答受け付けを閉じる
pubForm.setAcceptingResponses(false);
}
// 投票用フォームの全ての回答を公開用フォームにコピーする
function copyAll() {
// 公開用フォームの回答受け付けを開く
pubForm.setAcceptingResponses(true);
for (var i = 0; i < orgRes.length; i++) {
copy(orgRes[i])
}
// 公開用フォームの回答受け付けを閉じる
pubForm.setAcceptingResponses(false);
}
// 公開用フォームに回答をsubmitする関数
function copy(org) {
var items = org.getItemResponses();
var newRes = pubForm.createResponse();
for (var i = 0; i < items.length; i++) {
var item = items[i];
var itemType = item.getItem().getType();
// テキストボックス
if(itemType == FormApp.ItemType.TEXT){
var q = item.getItem().asTextItem();
}
// テキストボックス(長文)
if(itemType == FormApp.ItemType.PARAGRAPH_TEXT){
var q = item.getItem().asParagraphTextItem();
}
// ラジオボタン
if(itemType == FormApp.ItemType.MULTIPLE_CHOICE) {
var q = item.getItem().asMultipleChoiceItem();
}
// チェックボックス
if(itemType == FormApp.ItemType.CHECKBOX) {
var q = item.getItem().asCheckboxItem();
}
// プルダウン
if(itemType == FormApp.ItemType.LIST) {
var q = item.getItem().asListItem();
}
var res = q.createResponse(item.getResponse());
newRes.withItemResponse(res);
}
newRes.submit();
}
上記のコードで修正する箇所は2つ。投票用フォームのフォームIDを orgId に、公開用のフォームのフォームIDを pubId に代入してください。(2行目と7行目)
copy() はコアとなる関数で、公開用フォームに回答を追加するプログラムです。ここが一番苦労しました。Googleフォームの仕様で、回答を追加する際には、問題のタイプ(ラジオボタンやテキスト、チェックボックス、プルダウン等)を判別してセットしておかなければダメなんです。
Googleフォームごとに問題タイプをセットする方法だと汎用性がないので、回答のタイプを判別して自動でセットするようにプログラムを書きました。上記のコードはラジオボタン・テキスト・チェックボックス・プルダウンの4種類しか対応させてませんが、追加したい人はこことここを調べれば書き方が分かると思います。
3. 全ての回答を「公開用フォーム」にコピー
「投票用フォーム」で既に投票された全ての回答を「公開用フォーム」にコピーします。まだ投票前で回答が0個の場合は、ここの作業はスキップしてください。(2020/4/27追記:GASから「公開用フォーム」に投稿できるように権限を承認する必要があるので、回答が0個の場合でもcopyAll()を実行してください。)
全ての回答をコピーするには、先ほどのプログラムの中にある copyAll() 関数を使います。「投票用フォーム」のスクリプトエディタから、copyAll() を実行してください。
4. トリガーの設定
最後は、「投票用のフォーム」にトリガーを設定して、投票用の最新の回答が「公開用のフォーム」にコピーされるようにします。先ほどのプログラムの中にある copyRecent() 関数を使います。
これで、「投票用のフォーム」に新しい回答が増えると、「公開用のフォーム」にも自動で反映されるようになります。