Googleフォームで、ラジオボタン、プルダウン、チェックボックスといった選択肢に対して、定員(人数制限)を設定できる機能があると便利です。
例えば、「松の会」「竹の会」「梅の会」のような選択肢があり、それぞれに定員数が設定されている場合、定員に達した「松の会」が選択肢から自動的に消えることで、以降の申し込みを制限することができます。
このような定員制限機能は、イベントの申し込みなど、人数管理が重要な場面では必須と言えるでしょう。しかし、現在のGoogleフォームには、この機能が標準で搭載されていません。
そこでGAS(Google Apps Script)でうまく対応できないかと考えて、スクリプトを組んでみました。スプレッドシートの関数と組み合わせることで、とても応用の効くものができましたので、ここに投稿します。
それではテストのフォームを作りながら、このGASの使用方法を説明していきます。
テストのフォームとスプレッドシートを作る
フォーム
まず、以下のようなフォームを作ります。

とりあえずラジオボタンの質問を作ってください。
①質問、②選択肢、③説明で覚えてください。
スプレッドシート
フォームをスプレッドシートにリンクしてください。

リンクしたスプレッドシートに2枚目のシート(左から2番目のタブ)を作ります。このシートをGASが参照します。

①フォームの質問
②フォームの選択肢
③フォームの説明
④参照セル~ゼロ"0"より大きい任意の数値
①、②、③は、フォームと同じにしてください。
GAS
次にフォームからGAS(updateItems)を登録します。

次のGASをフォームのエディタにコピペしてください。
- function updateItems(SheetNo){
- //アクティブフォーム
- const form = FormApp.getActiveForm();
- //選択肢シート:SheetNoは必要なら変更する(一番左のシートが0、2番目が1、3番目が2…)
- if(!(SheetNo>1)) SheetNo = 1;
- const itemsSheet = SpreadsheetApp.openById(form.getDestinationId()).getSheets()[SheetNo];
- //シートの選択肢、説明などを配列で取得する
- const lastRow = itemsSheet.getLastRow();
- const itemsList = itemsSheet.getRange(1,1,lastRow,3).getDisplayValues();
- //変数宣言
- let newItems = []; let countItems = 0;
- //説明1を取得
- let helpText = itemsList[0][1];
- for (let i = 1; i < lastRow; i++) {
- //参照セルがゼロでない選択肢を取得する
- if (itemsList[i][2] > 0) {
- newItems[countItems++] = itemsList[i][0];
- }
- // 追加の説明2〜を取得する
- if (itemsList[i][1] != "") {
- helpText += "\n" + itemsList[i][1];
- }
- }
- if (countItems > 0) {
- //フォームの質問、説明、選択肢などを取得する
- const items = form.getItems();
- for (let i = 0; i < items.length; i++) {
- //対象の質問を探して見つけたら…
- if (items[i].getTitle() === itemsList[0][0]) {
- //選択肢のタイプ(ラジオボタン or プルダウン or チェックボックス)を選んで…
- switch (items[i].getType()) {
- //ラジオボタンの選択肢と説明を更新する
- case FormApp.ItemType.MULTIPLE_CHOICE:
- items[i].asMultipleChoiceItem().setChoiceValues(newItems).setHelpText(helpText); break;
- //プルダウンの選択肢と説明を更新する
- case FormApp.ItemType.LIST:
- items[i].asListItem().setChoiceValues(newItems).setHelpText(helpText); break;
- //チェックボックスの選択肢と説明を更新する
- case FormApp.ItemType.CHECKBOX:
- items[i].asCheckboxItem().setChoiceValues(newItems).setHelpText(helpText); break;
- }
- break;
- }
- }
- }
- //選択肢の参照セルが全てゼロなので回答受付を終了する
- else {
- if(form.isAcceptingResponses()) { //UpdateItemsを同じフォームで複数使うための対策
- form.setAcceptingResponses(false);
- //回答受付終了をメールで知らせる
- const formName = form.getTitle();
- const formUrl = form.getEditUrl() + "#responses";
- const mailAdd = Session.getActiveUser().getEmail();
- const mailTitle = "フォーム<" + formName + ">が受付終了になりました。";
- const mailText = "フォーム<" + formName + ">が受付終了になりました。\n" + formUrl;
- GmailApp.sendEmail(mailAdd, mailTitle, mailText);
- }
- }
- return countItems;
- } //Ver1.5.7 for maintenance
↓ ↓ コピペ ↓ ↓ (コピペ後は保存をしてください。)

トリガー
つぎにトリガーを追加します。

イベントの種類の選択は、「フォーム送信時」を選びます。

※承認を求められたら、「Advanced」(あるいは、「詳細」)→「Go to ~~(Unsafe)」(あるいは、「~~に移動」)→「Allow」(あるいは、「許可」)

ここまでで準備ができました。
動作テスト
作成したシート(2枚目)の数値(参照セル:C3)をゼロ"0"にしてください。

フォームを実行(プレビュー)します。

回答後、送信してください。

再度、フォームをプレビューしてください。

参照セルをゼロ"0"にした選択肢の項目が消えていたら、成功です。
実践編
ここまでが、GAS(updateItems)を追加したフォームの基本動作です。
この基本動作をもとに、自分で作るフォームに応用していきます。
既存のフォームを修正変更し、改めて回答を募集する際は、過去のデータが混ざらないよう、リンクしたスプレッドシートとフォームの回答を全削除してください。(以下の①②の作業)
①回答シートの回答行を削除する。

②フォームの回答を削除する

応用例その1
次に、このテストフォームを使った応用例を示してみます。
選択肢シート(2枚目のシート)に、新たな項目と関数を加えています。
(数式で表示:[Ctrl]+@)

テストのフォームよりの回答・送信を(15回)繰り返しました。その時の回答シートです。

この時の選択肢シート(2枚目のシート)には、次のように表示されています。

① =COUNTIF('フォームの回答' !C:C, A2)
フォームとリンクしている"フォームの回答"シートに記録されている"お茶の会"のカウント数(参加者数)
② =E2-D2
定員数(任意)から参加者数を引いた残りの席数
③ =if(C2>0, "", A2 & "は定員に達しました")
残りの席数が"0"以下のとき、"お茶の会は定員に達しました"と表示
この時のフォームのプレビューです。

お分かりでしょうか?
回答の選択項目をカウントして、定員数に達した項目が選択肢から消えています。
また、その消えた項目の旨を説明にて表示しています。
このように、選択肢シート(2枚目のシート)に関数と組み合わせることで、自分の作るフォームの質問の選択肢に応用の幅が広がります。
その他、説明
すべての項目が定員に達したら...
選択肢の参照セル(④C列のセル)がすべてゼロ"0"以下の値になると、強制的に回答受付終了となるようにGASに組まれています。同時に、フォームのオーナーへ回答受付終了のメールを送ります。


選択肢のタイプ
選択肢のタイプは、ラジオボタン、プルダウン、チェックボックスの3種類があります。
GASで自動的にタイプを判断しますので、自由に選んでください。
選択肢の項目が多い場合は、プルダウンの方が見た目も使い勝手も良いですね。
シートタブの位置
選択肢シートのタブの位置(左から2番目)を替えたいときは、UpdateItems(SheetNo)の引数を使ってください。引数SheetNoは、タブの位置が3番目は"2"、4番目は"3"…です。
その他、応用例
updateItemsを使った応用例を作ってあります。
ご参考になりましたら幸いです。
既存のフォームを修正変更し、改めて回答を募集する際は、過去のデータが混ざらないよう、リンクしたスプレッドシートとフォームの回答を全削除してください。(以下の①②の作業)
①回答シートの回答行を削除する。

②フォームの回答を削除する

応用例その2(残席数をフォームに表示する)
応用例その3(残席数をフォームの選択肢に表示する)

応用例その4(1~3人の申込みにも定員のある選択肢で対応)
応用例その5(チェックボックスで定員のある選択肢に対応)
応用例その6(定員に申込締切日を追加)
応用例その7(複数の質問の選択肢に定員を設定)
これまでの応用例は一つの質問の選択肢だけの対応ですが、この応用例7を使うことで、複数の質問の選択肢に定員を設定できます。
フォームの回答者数で制限する ~ multiReplyの紹介
updateItemsは、「質問の選択肢」ごとに制限(定員、人数制限)を設けられますが、multiReplyは単純にフォーム全体の回答者数に制限が設けられます。さらに、返信メールにも対応していますので、簡単なフォームであればこれで十分かもしれません。
Googleフォームでとにかく簡単に申し込み人数制限を設定したい方はこちら
おわりに
GASで複雑な処理を行うスクリプトを組むと、様々なフォームに応用させるのが難しくなります。GASの処理は単純で、スプレッドシートの関数で応用できるのが私の好みです。フォームに自分のアイデアを採用するためテストする時、関数はトライ&エラーが簡単ですからね。ちなみに今(執筆時)、選択肢の項目に残数を表示する方法を思いついたので試しています。(済)
以上、このGASが皆様のフォームの開発に役立つことを願いまして、それではまた。
追記、google公式サイトのApps Scriptリファレンスを見ていると、今まで見落としていたgetTypeを見つけました。
これで、ラジオボタンとプルダウンを自動で区別できるようになりました。よかったよかった^o^(Ver.1.3.0)
追記、チェックボックスへの対応も問題ないことが分かりましたので、GAS(updateItems)へチェックボックスも追加しました。(Ver.1.4.0)
追記、UpdateItemsの複数同時使用に対して、複数の終了メールに対策しました。(Ver.1.4.5)
追記、GASの仕様変更によるエラー対応のため、コードに変更を加えました。(Ver.1.5.5)
今までは.setHelpTextはセクション毎に設定できていましたが、
例) Item.setHelpText('文字列');
2024/10月以降のGASのアップデート(?)から、セクションのタイプ毎にキャストする必要があるようです。
例) Item.asMultipleChoiceItem().setHelpText('文字列');
参考) https://support.google.com/docs/thread/300175092?hl=en
情報をいただいた二月様、たくさん様に感謝です。m(_ _)m
バグ等ありましたら、お知らせいただくと幸いです。
コメント
大変貴重な情報をありがとうございます。
こちらの記事を参考にフォームの作成にトライしております。
こちらを実行すると
Exception: Unexpected error while getting the method or property setHelpText on object FormApp.Item.
とエラーが返ってきて止まってしまいました。
確認したところ44行目の
items[i].setHelpText(helpText); break;
で上記のエラーが発生してしまっている状況です。
私が作ろうとしているフォームでは、説明はそこまで重要ではないのでこの行をコメントアウトしたところその他は問題なく機能したのでとりあえずその状態で運用しているのですが、どうすればこのエラーが出なくなるかもし何かお分かりになりましたら教えていただけないでしょうか。
どうぞよろしくお願いいたします。
当ブログをご覧いただきありがとうございます。
ご質問の回答です。
一度回答受付を終了して、再度フォームの質問を始めるときはフォームの選択肢で消えた項目は、再度追加してください。(選択シートのA2~をフォームの選択肢にコピペするのが確実です。)
この時の注意点としてフォームの回答の件数とスプレッドシートの回答数に気を付けてください。
できましたら、フォームで「すべての回答を削除」とスプレッドシートに回答のある行を削除してから始められると確実です。
参照セルについて、少し詳しく説明しますと、
C列の2行以降(C2~)の参照セルの値が0以下の値(<=0)になったら、次のフォームの実行時にそのセルの左隣のA列の値(C2に対してA2)がフォームの選択肢から削除されます(A列の値は消えません)。 逆の場合を考えると、参照セルの値が0より大きい値(>0)になったらフォームの選択肢に追加されます。
これが理解できますと、回答終了までに選択肢の項目が増えたり減ったりなどが自在に行えます。
色々と試していただけたらと思います。
回答になりましたでしょうか。
お世話になります。
本記事を参考にフォーム作成を試み、定員に達したら選択肢が消えるところまではできました。
そこでご質問ですが、一回消えた選択肢を再び表示するにはどうすれば良いでしょうか。
こちらこそ、久しぶりにGASに触れて楽しかったです。
また何かお気付きになりましたら、お知らせください。
ご回答いただき、ありがとうございました。
質問方法を変えることで対応することができました。
初めてこういったコードなるものを触る機会でしたが、大変面白かったです。
貴殿のブログに出会えて良かったです。
当ブログをご覧いただきありがとうございます。
セクションをご利用のフォームの質問に当スクリプトをお使いになるとは、勇者ですね。
簡単なフォームでテストしてみましたが、なるほど確かに選択肢が消えると、セクションへのルートもなくなりますね。
これは当たり前で、このスクリプトは、シートの情報で選択肢を更新することを送信毎に行っています。
ですので、選択肢に付けたセクションへの移動情報が消されてしまいます。
対応方法は、大幅なスクリプトの書き直しになりますし、今考えただけでは汎用性のある方法が思いつきません。
申し訳ありませんが、選択肢にセクションの移動が付いた場合は、非対応とさせていただきます。
貴重な情報をいただきありがとうございました。
お世話になっております。
本記事を参考にフォーム作成を試みております。
定員に達したら選択肢が消えるところまでは再現できたのですが、
とある選択肢が消えると他の選択肢に設定した指定のセクションに飛ばす設定が消えてしまいます。
本件いかように対応したらよろしいでしょうか。
ご教示いただけますと幸いです。
どうぞよろしくお願いします。
当ブログをご覧いただきありがとうございます。
まず最初に確認したいのですが、「回答を1回に制限する」を使用すると、フォームの回答者がGoogleアカウント所有者であることが必要です。
もしフォームから回答が不特定多数になるのでしたらこの機能を使うことは現実的ではありません。
また、Googleアカウント所有者であれば、必ずスプレッドシートに回答は記録されます。確実にフォームとスプレッドシートがリンクされているでしょうか?
今一度ご確認いただけたらと思います。
お世話になります。
GASは意味も分からず、WEBにあるものをコピペして使用している理解度の者です。
この度、急遽仕事でこのようなフォームの作成が必要でこの方法を探していました。
大変助かりました。ありがとうございます。
ただ、一つだけご教授いただけたらと思いましてコメントさせていただきます。
今回、応用例その7を使わさせていただく予定なのですが、フォームの設定で「回答を1回に制限する」をチェックしますと、フォームからのデータがスプレットシートに反映されないということを確認しました。
同一者からの2重送信を防ぐためにも設定したいのですが、どうすれば宜しいでしょうか?
何卒よろしくお願いします。
ありがとうございました。
また、わからないところがありましたら、
ご教示、よろしくお願いいたします。