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 count = 0;
- //説明1を取得
- let helpText = itemsList[0][1];
- for (let i = 1; i < lastRow; i++) {
- //参照セルがゼロでない選択肢を取得する
- if (itemsList[i][2] > 0) {
- newItems[count++] = itemsList[i][0];
- }
- // 追加の説明2〜を取得する
- if (itemsList[i][1] != "") {
- helpText += "\n" + itemsList[i][1];
- }
- }
- if (count > 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 title = "フォーム<" + formName + ">が受付終了になりました。";
- const text = "フォーム<" + formName + ">が受付終了になりました。\n" + formUrl;
- //メールを送る
- GmailApp.sendEmail(mailAdd, title, text);
- }
- }
- } //Ver1.5.5 for maintenance
今までは.setHelpTextはセクション毎に設定できていましたが、
例) Item.setHelpText('文字列');
2024/10月以降のアップデート(?)から、セクションのタイプ毎にキャストする必要があるようです。
例) Item.asMultipleChoiceItem().setHelpText('文字列');
参考) https://support.google.com/docs/thread/300175092?hl=en
情報をいただいた二月様、たくさん様に感謝です。m(_ _)m
↓ ↓ コピペ ↓ ↓ (コピペ後は保存をしてください。)
トリガー
つぎにトリガーを追加します。
イベントの種類の選択は、「フォーム送信時」を選びます。
※承認を求められたら、「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は単純にフォーム全体の回答者数に制限が設けられます。さらに、返信メールにも対応していますので、簡単なフォームであればこれで十分かもしれません。
おわりに
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;
で上記のエラーが発生してしまっている状況です。
私が作ろうとしているフォームでは、説明はそこまで重要ではないのでこの行をコメントアウトしたところその他は問題なく機能したのでとりあえずその状態で運用しているのですが、どうすればこのエラーが出なくなるかもし何かお分かりになりましたら教えていただけないでしょうか。
どうぞよろしくお願いいたします。
当ブログをご覧いただきありがとうございます。
ご質問のエラーですが、只今PCがネットに繋げない環境にいますので、実際にテストを行うことができないことをご了承ください。
さて、updateItemsのコードはそのままコピペして運用されているとして考えますと、シート1の記述を再度確認していただけたらと思います。
ABC列のセルに何か必要以外の記入はないでしょうか?
例えば、かなり下の方の行に文字が入っているセルがある…などです。
あとはすみませんが、今は思いつかないですね。
お忙しい中でコメントありがとうございます。はい、コードはそのまま使用させていただいています。
いろいろ試していたのですが、説明自体はちゃんとフォームに反映されているのですが、そのあとでエラーが出ている状況でした。
シート1またはフォーム自体を作り直すなどもう少し色々試してみたいと思います。
何かエラーの出るパターンなどが分かりましたら是非、教えてくださいね。
お忙しい中アップデートありがとうございます!無事に動かすことができました、感謝感謝です。
まさかちょうどGASのアップデートのタイミングで導入してしまっていたとは(汗)
本当にありがとうございました
こちらこそ、ありがとうございました。
二月さんのお陰でエラーに気付くことができました。
また何か問題がありましたら、お知らせください。
自分も同じエラーに悩まされました。
最近のGASのアップデートで仕様が少し変更され、以下のようにコードを変更する必要があります。
こちらに変更することで解決しました。
新しいセクションの説明の追加の場合
`items.setHelpText()`→`item.asSectionHeaderItem().setHelpText()`
タイトルの説明の追加の場合
`items.setHelpText()`→`item.asPageBreakItem().setHelpText()`
参考URL
https://support.google.com/docs/thread/300175092?hl=en
たくさん様、
エラーのご指摘と対応方法などほんと~~~にありがとうございます。
現在、マイPCが使えない状態なのですが、友人のノートPCとスマホのテザリングで何とかフォームのテストをしてみました。(Googleの開発環境は、だれのPCでもすぐにテストできるのはすごいですね。)
エラーが確認できました。最近のGASのアップデートが原因なのですね。
たくさん様からのリンク情報でコードの修正点も確認できて変更を加えました。(Ver 1.5.5に更新しました。)
https://support.google.com/docs/thread/300175092?hl=en&msgid=300259237
Google様は相変わらずの唯我独尊ですね。使用者のことはお構いなしに、いつの間にか細々なことを変更してしまうんですよね。私らはネットで同志を探して解決するしかないんですね。
たくさん様、今回は本当に助かりました。お手数ですがまた何か見つかりましたら、教えていただけますでしょうか?
お世話になります。
本記事を参考にフォーム作成を試み、定員に達したら選択肢が消えるところまではできました。
そこでご質問ですが、一回消えた選択肢を再び表示するにはどうすれば良いでしょうか。
当ブログをご覧いただきありがとうございます。
ご質問の回答です。
一度回答受付を終了して、再度フォームの質問を始めるときはフォームの選択肢で消えた項目は、再度追加してください。(選択シートのA2~をフォームの選択肢にコピペするのが確実です。)
この時の注意点としてフォームの回答の件数とスプレッドシートの回答数に気を付けてください。
できましたら、フォームで「すべての回答を削除」とスプレッドシートに回答のある行を削除してから始められると確実です。
参照セルについて、少し詳しく説明しますと、
C列の2行以降(C2~)の参照セルの値が0以下の値(<=0)になったら、次のフォームの実行時にそのセルの左隣のA列の値(C2に対してA2)がフォームの選択肢から削除されます(A列の値は消えません)。 逆の場合を考えると、参照セルの値が0より大きい値(>0)になったらフォームの選択肢に追加されます。
これが理解できますと、回答終了までに選択肢の項目が増えたり減ったりなどが自在に行えます。
色々と試していただけたらと思います。
回答になりましたでしょうか。
お世話になっております。
本記事を参考にフォーム作成を試みております。
定員に達したら選択肢が消えるところまでは再現できたのですが、
とある選択肢が消えると他の選択肢に設定した指定のセクションに飛ばす設定が消えてしまいます。
本件いかように対応したらよろしいでしょうか。
ご教示いただけますと幸いです。
どうぞよろしくお願いします。
当ブログをご覧いただきありがとうございます。
セクションをご利用のフォームの質問に当スクリプトをお使いになるとは、勇者ですね。
簡単なフォームでテストしてみましたが、なるほど確かに選択肢が消えると、セクションへのルートもなくなりますね。
これは当たり前で、このスクリプトは、シートの情報で選択肢を更新することを送信毎に行っています。
ですので、選択肢に付けたセクションへの移動情報が消されてしまいます。
対応方法は、大幅なスクリプトの書き直しになりますし、今考えただけでは汎用性のある方法が思いつきません。
申し訳ありませんが、選択肢にセクションの移動が付いた場合は、非対応とさせていただきます。
貴重な情報をいただきありがとうございました。
ご回答いただき、ありがとうございました。
質問方法を変えることで対応することができました。
初めてこういったコードなるものを触る機会でしたが、大変面白かったです。
貴殿のブログに出会えて良かったです。
こちらこそ、久しぶりにGASに触れて楽しかったです。
また何かお気付きになりましたら、お知らせください。
お世話になります。
GASは意味も分からず、WEBにあるものをコピペして使用している理解度の者です。
この度、急遽仕事でこのようなフォームの作成が必要でこの方法を探していました。
大変助かりました。ありがとうございます。
ただ、一つだけご教授いただけたらと思いましてコメントさせていただきます。
今回、応用例その7を使わさせていただく予定なのですが、フォームの設定で「回答を1回に制限する」をチェックしますと、フォームからのデータがスプレットシートに反映されないということを確認しました。
同一者からの2重送信を防ぐためにも設定したいのですが、どうすれば宜しいでしょうか?
何卒よろしくお願いします。
当ブログをご覧いただきありがとうございます。
まず最初に確認したいのですが、「回答を1回に制限する」を使用すると、フォームの回答者がGoogleアカウント所有者であることが必要です。
もしフォームから回答が不特定多数になるのでしたらこの機能を使うことは現実的ではありません。
また、Googleアカウント所有者であれば、必ずスプレッドシートに回答は記録されます。確実にフォームとスプレッドシートがリンクされているでしょうか?
今一度ご確認いただけたらと思います。
ありがとうございました。
また、わからないところがありましたら、
ご教示、よろしくお願いいたします。
早速のご回答ありがとうございます。
最終的にやりたいのは「応用例その7」に近いものですが、
とりあえず、このページの例をそのままやってみておりました。
あらためてやってみましたら、うまく動作いたしました!
もしかすると、今までトリガーの設定で
「イベントの種類を選択」で「フォーム送信時」にせず
「起動時」のままにしていたかもしれません。
お騒がせいたしました。
とりあえず、練習(勉強)のため作例通りに作成してみて
いずれ「応用例その7」にもチャレンジしてみようと思っております。
このようなサイトを公開していただき、感謝しております。
ありがとうございました。
無事に動作したようで何よりです。
私のスクリプトを使ってのGoogleフォームの開発は、GASの勉強よりシートの関数の勉強になるとは思いますが、頑張ってください。
お世話になります。
GASは意味も分からず、WEBにあるものをコピペして使用している程度です。
今回も検索をして貴サイトにたどり着きました。
私がやりたいことは、ほぼ「応用例その7」と同じもので、
注文数をプルダウンから選択するのではなく、
注文数を数値で入力するものを作成しようと思っております。
まずは、作例そのままでやってみようと思い手順通り進めましたが、
すべての応用例で使用している「updateItems」がエラーになってしまいます。
TypeError: Cannot read properties of null (reading ‘getDestinationId’)
updateItems @ コード.gs:6
デバックをすると6行目で止まってしまいます。
何度かチャレンジしましたが、全く同じで解決できませんでした。
コピペしたのはVer1.4.5です。
大変恐縮ですが、何が原因か、また解決方法等お分かりになりましたらご教示願えますでしょうか。
よろしくお願いいたします。
まずはGASの初心者にも関わらず当記事を試してくださりありがとうございます。
応用例その7は少し複雑なUpdateItemsの使用例なので混乱させてしまったかもしれませんね。
もう少し簡単な説明ができないものかと少しづつ加筆していますが、なにしろエンジニア脳なもので・・・。
さてご質問の件ですが、GoogleフォームのスクリプトエディタでUpdateItemsをコピペした後、
function myFunction() {
updateItems(1);
updateItems(2);
}
をUpdateItemsの後に追加されたでしょうか?
エディタから実行テストするのでしたら、このmyFunctionを実行してください。
またトリガーに追加するのもUpdateItemsでなくmyFunctionですのでお間違えがないでしょうか?
この点を間違えてなくまだエラーが出るようでしたら、再度ご連絡をお願いします。
追記ですが、このUpdateItemsは、プルダウン、ラジオボタン、チェックボックスに対応しますので「注文数を数値で入力」は対象外となっております。ご了承くださいませ。
役に立つ情報ありがとうございます。
この様なスクリプトを探していました。
しかし、コピペで使用してみましたが、
「構文エラー: SyntaxError: Invalid or unexpected token 行: 21 ファイル: コード.gs」
と出てスクリプトが保存出来ず、以降の作業もできません。
ご指示していただければ幸いです、よろしくお願い致します。
ご報告をありがとうございます。
昨日にリクエストでこのUpdateItemsに少し機能追加を行いました。
そのときにコードをHTMLに変換する際に、ダブルクォーテーション(“”)が正しく変換されなかったようです。^^;
修正し確認をしましたので大丈夫かと思います。再度お試しください。
ご迷惑をお掛けしました。
早速のご対応ありがとうございます。
無事テストまでたどり着けました。
同様にして選択肢が削除されるところまでは出来ました。
しかし、応用編の様に関数を使用すると、スプレッドシート上で関数エラーが出てしまいます。
他の応用編2~の関数もコピペしてみましたが同様です。
対応策あるでしょうか?御教授ください。
度々のバグのご指摘に感謝いたします。
原因は半角の”が全角に変換されていることで私の一方的なミスです。
これはWordPressの仕様なので強制的にこの機能を止めていたのですが、少し前のテーマの変更でこの操作が無効になっていました。
また操作を加えましたので、全角変換は行われないはずです。
ご迷惑をお掛けしました。
お手数ですが、また何か問題が見つかりましたらお知らせください。
何度もご対応ありがとうございます。
素人な物で半角全角に違いに気づかずコピペのみで作業していました。
おかげさまで無事動作確認も取れ、本番使用したいフォームにも組み込むことができました。
この度はありがとうございました。
いいえ、これは私のミスです。ご指摘がありませんでしたら、このまま気づかず被害が拡大していました。
今回はとても助かりました。また何か見つけましたらよろしくお願いします。
余談ですが、もし回答送信後の返信メール機能も追加することになりましたら、
スクリプトのDiyReply(【GAS】Googleフォームから自動で返信メール~合計金額など好きな値を追加できる自由度の高い返信メール)をUpdateItemsと同時使用することをおすすめします。
返信メールがいくつかあって混乱するそうです(今は2つだけにしていますが)。