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
バグ等ありましたら、お知らせいただくと幸いです。
コメント
早速のお返事、ありがとうございました。
こども食堂を応援してくださって、嬉しいです!
「フォームの回答を全削除」と「スプレッドシートの回答行を削除」をした上での再試行、
先程6回行ってみましたので、結果をご報告いたします。
うち5回はKasuga様と同じく、最終回答者が「別の回答を送信」をクリックすると、受付終了画面になっていました。
ただ何故1回は、「別の回答を送信」をクリックすると、申込フォームが開き、入力も可能で、
入力後に送信ボタンを押すと、「受付は終了しました」の画面が表示されました。
※入力中は、画面左下に「下書きを保存できません」というメッセージが何度か表示されました。
前回投稿させていただく前にも、数回同じように試行してみたのですが、
その際は、毎回後者の状態でした。
今回、何か条件が違ってしまわないように、送信ボタンを押した後に「別の回答を送信」をクリックするまでの
時間などは同じような感じで行ったつもりなのですが、何故こうなったのか、分かりません。。
一点、お伝えしていなかった条件といたしましては、
私はフォームで「選択肢に定員を設定」はしておらず、
シンプルに「スプレッドシートのC列のセルが0になったら、フォームを閉じる」という形で
このページにあるGASを使わせていただいています。
そのことが原因であったなら、申し訳ありません。
再現が部分的でもやもやしてしまいましたが、
また何か分かったらご報告させていただきます。
※「別の回答を送信」の設定は、私も最近まで使ったことがありませんでした。
こども食堂のお仲間に上限設定の方法を共有したいと思って、その食堂のフォームを見せてもらったら、
そこに「別の回答を送信」がありまして、そこで初めて気づいた次第です。
ありがとうございました!
当ブログをご覧いただきありがとうございます。
私も試してみました。しかし、最終回答者が「別の回答を送信」を使うと「~回答の受け付けは終了しました。」の回答受付終了メッセージが表示されて正しく動作しているように思えます。
考えますに、このスクリプト(GAS)は回答送信後に実行されます。そのため最終回答者のあまりに素早い「別の回答を送信」のクリックで、スクリプトの受付終了に切替えるプロセスの前にフォームにアクセスできるのかな???とも考え試してみましたが私の環境では再現できませんでした。
できましたら、「フォームの回答を全削除」と「スプレッドシートの回答行を削除」してもう一度最初から試していただけますでしょうか。
同じ様な結果が繰り返されるようでしたらお知らせいただけますと助かります。
お恥ずかしい話、この「別の回答を送信」は今まで使ったことがありませんでした。私は設定でこのリンクを消していたのですね。

こども食堂を応援しております。頑張ってください。
とても有益な情報をシェアしてくださり、心から感謝いたします。
こども食堂の申込フォームに利用させていただいております。
一点、気づいたこと&希望事項についてご連絡させていただきます。
申込が上限数に達した後、GoogleフォームのURLへ飛ぶと、
確かに回答受付が終了されている状態になるのですが、
最終回答者(上限10人設定のフォームであれば、10人目の回答者)の
フォーム入力後に表示される「回答を記録しました」というページの下部にある
「別の回答を送信」という箇所からフォームに飛ぶと、
回答受付が終了されておらず、フォーム入力が可能な状態になってしまっているようです。
「別の回答を送信」を非表示にすれば問題はないのですが、
フォームの活用方法によっては、非表示にすると不便になることがあります。
つきましては、「別の回答を送信」という箇所からフォームに飛んだ場合でも
回答受付が終了されるようになるととても助かるのですが、可能でしょうか。
※私はプログラミングに関しては全くの素人なので、コード等の意味は理解しておりません。
もし私の利用方法等が間違っている場合は、大変申し訳ありません。
こちらこそ、ありがとうございました。
二月さんのお陰でエラーに気付くことができました。
また何か問題がありましたら、お知らせください。
お忙しい中アップデートありがとうございます!無事に動かすことができました、感謝感謝です。
まさかちょうどGASのアップデートのタイミングで導入してしまっていたとは(汗)
本当にありがとうございました
たくさん様、
エラーのご指摘と対応方法などほんと~~~にありがとうございます。
現在、マイPCが使えない状態なのですが、友人のノートPCとスマホのテザリングで何とかフォームのテストをしてみました。(Googleの開発環境は、だれのPCでもすぐにテストできるのはすごいですね。)
エラーが確認できました。最近のGASのアップデートが原因なのですね。
たくさん様からのリンク情報でコードの修正点も確認できて変更を加えました。(Ver 1.5.5に更新しました。)
https://support.google.com/docs/thread/300175092?hl=en&msgid=300259237
Google様は相変わらずの唯我独尊ですね。使用者のことはお構いなしに、いつの間にか細々なことを変更してしまうんですよね。私らはネットで同志を探して解決するしかないんですね。
たくさん様、今回は本当に助かりました。お手数ですがまた何か見つかりましたら、教えていただけますでしょうか?
自分も同じエラーに悩まされました。
最近のGASのアップデートで仕様が少し変更され、以下のようにコードを変更する必要があります。
こちらに変更することで解決しました。
新しいセクションの説明の追加の場合
`items.setHelpText()`→`item.asSectionHeaderItem().setHelpText()`
タイトルの説明の追加の場合
`items.setHelpText()`→`item.asPageBreakItem().setHelpText()`
参考URL
https://support.google.com/docs/thread/300175092?hl=en
何かエラーの出るパターンなどが分かりましたら是非、教えてくださいね。
お忙しい中でコメントありがとうございます。はい、コードはそのまま使用させていただいています。
いろいろ試していたのですが、説明自体はちゃんとフォームに反映されているのですが、そのあとでエラーが出ている状況でした。
シート1またはフォーム自体を作り直すなどもう少し色々試してみたいと思います。
当ブログをご覧いただきありがとうございます。
ご質問のエラーですが、只今PCがネットに繋げない環境にいますので、実際にテストを行うことができないことをご了承ください。
さて、updateItemsのコードはそのままコピペして運用されているとして考えますと、シート1の記述を再度確認していただけたらと思います。
ABC列のセルに何か必要以外の記入はないでしょうか?
例えば、かなり下の方の行に文字が入っているセルがある…などです。
あとはすみませんが、今は思いつかないですね。