質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
G Suite

G Suiteは、Google AIが組み込まれたセキュアでクラウドネイティブのコラボレーションアプリや生産性向上アプリを1つにまとめた統合スイートです。Gmail、ドキュメント、ドライブ、カレンダー、Meet などが含まれます。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Q&A

解決済

1回答

252閲覧

GoogleフォームとGASについて

syababa

総合スコア1

G Suite

G Suiteは、Google AIが組み込まれたセキュアでクラウドネイティブのコラボレーションアプリや生産性向上アプリを1つにまとめた統合スイートです。Gmail、ドキュメント、ドライブ、カレンダー、Meet などが含まれます。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

0グッド

1クリップ

投稿2025/01/31 07:33

実現したいこと

Googleフォームで予約フォームを作りたい。
製品A~Fの6種類があり、選択後各セクションに飛んで日付をラジオボタンで選択。
その選択肢を一度予約が入ったら選択肢から削除されるようにしたい。
例:製品A→13日10時~が送信された場合、製品Aの13日10時~の選択肢を削除する。

発生している問題・分からないこと

asMultipleChoiceItemが上手く機能せず、エラーが発生してしており、
変数を確認しても条件を満たしている気がしてなりません。
当方GASを組み始めての経験が浅く、Geminiに聞きながらの構築になります。

エラーメッセージ

error

1TypeError: item.asMultipleChoiceItem(...).getResponse is not a function 2 at onFormSubmit(コード:45:55)

該当のソースコード

GAS

1function onFormSubmit(e) { 2 var formResponse = e.response; 3 var itemResponses = formResponse.getItemResponses(); 4 5 var product = itemResponses[5].getResponse(); 6 7 var properties = PropertiesService.getDocumentProperties(); 8 var selectedTimes = properties.getProperty(product); 9 selectedTimes = selectedTimes ? JSON.parse(selectedTimes) : []; 10 11 var form = FormApp.getActiveForm(); 12 var items = form.getItems(); 13 14 var sectionIndex = getProductSectionIndex(product, items); 15 16 if (sectionIndex !== undefined && sectionIndex < items.length - 1) { 17 var itemIndex = sectionIndex + 1; 18 19 if (itemIndex < items.length) { 20 var item = items[itemIndex]; 21 22 if (item && item.getType() === FormApp.ItemType.MULTIPLE_CHOICE) { 23 var meetingTime = item.asMultipleChoiceItem().getResponse()[0]; 24 selectedTimes.push(meetingTime); 25 properties.setProperty(product, JSON.stringify(selectedTimes)); 26 updateMeetingTimeChoices(item, selectedTimes); 27 } 28 } 29 } 30} 31 32function getProductSectionIndex(product, items) { 33 var productSections = { 34 "製品A": "製品A", 35 "製品B": "製品B", 36 "製品C": "製品C", 37 "製品D": "製品D", 38 "製品E": "製品E", 39 "製品F": "製品F" 40 }; 41 42 for (var i = 0; i < items.length; i++) { 43 if (items[i].getType() === FormApp.ItemType.PAGE_BREAK && items[i].getTitle() === productSections[product]) { 44 return i; 45 } 46 } 47 return undefined; 48} 49 50function updateMeetingTimeChoices(sectionItem, selectedTimes) { 51 if (sectionItem && sectionItem.getType() === FormApp.ItemType.MULTIPLE_CHOICE) { 52 var originalChoices = ["13日(木) 10時~", "13日(木) 11時~", "13日(木) 13時~", "13日(木) 14時~", "14日(金)10時~", "14日(金)11時~", "14日(金)13時~", "14日(金)14時~"]; 53 var availableChoices = originalChoices.filter(function(choice) { 54 return selectedTimes.indexOf(choice) === -1; 55 }); 56 57 if (availableChoices.length > 0) { 58 sectionItem.asMultipleChoiceItem().setChoiceValues(availableChoices); 59 } 60 } 61}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

セクションを跨いだフォームの修正が記載されたサイトを見つける事が出来ませんでした。
変数の確認をログの出力で行っており、私の目からは問題ないように見えるのですが、エラーを改善できませんでした。

補足

https://docs.google.com/forms/d/e/1FAIpQLScPZ2huyCfVqsAuC9SKD6wNR5SS-kgq7IQIcgkZ3kR8ymI9Bw/formResponse

こちらは当該のGoogleフォームです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YellowGreen

2025/01/31 15:17 編集

1) エラーになっているgetResponseは質問項目ではなく回答のメソッドですね その箇所ではmeetingTimeとして回答の日時を処理しなければならないので 取得すべきは質問項目のインデックスではなく回答のインデックスなのでは? 2) 日時を選んだ後は別のセクションに飛ぶか回答を送信するのであれば、 ラジオボタンの選択肢の設定は、 setChoiceValues(values)メソッドではなく setChoices(choices)メソッドとして choices選択後の処理を指定しておいた方がよいかと… Geminiさんにその辺を相談してみてください なお、 現在のコードはキャンセル対応や 新たな日時の設定などができないので あまり実用的ではないと思いますよ
guest

回答1

0

ベストアンサー

あまり実用的ではないのではというコメントをしていますが、
キャンセル対応や選択肢の設定などを手動で行う前提で
加筆・修正したコードです

実際のフォームを拝見できていないのでエラーなく動作するかどうか不明ですが
当方の環境では動作しています
参考になれば…

JavaScript

1// プロパティーサービスに保存されている予約済みの選択肢を表示 2function showAllProperties() { 3 const properties = PropertiesService.getDocumentProperties(); 4 const keys = properties.getKeys(); 5 for (const key of keys) { 6 const dateTimes = JSON.parse(properties.getProperty(key)); 7 console.log('製品: %s', key); 8 for (const dateTime of dateTimes) { 9 console.log('予約済み:%s', dateTime); 10 } 11 console.log('--'); 12 } 13} 14 15// プロパティーサービスに保存した予約済みの選択肢をすべて消去 16function deleteAllProperties() { 17 const properties = PropertiesService.getDocumentProperties(); 18 properties.deleteAllProperties(); 19} 20 21// 引数に指定した製品の質問項目の選択肢を初期値で更新 22function updateChoices(product = '製品F') { 23 const form = FormApp.getActiveForm(); 24 const items = form.getItems(); 25 const index = getProductSectionIndex_(product, items); 26 const item = items[index + 1]; 27 updateMeetingTimeChoices_(item, '_'); 28} 29 30// すべての製品の選択肢を初期値で更新 31function updateAllChoices() { 32 const products = [ 33 '製品A', 34 '製品B', 35 '製品C', 36 '製品D', 37 '製品E', 38 '製品F', 39 ] 40 for (const product of products) { 41 console.log('%s を処理中…', product); 42 updateChoices(product); 43 } 44} 45 46// フォームの選択肢から回答のあったものを削除 47function onFormSubmit(e) { 48 if (!e) { 49 console.log('エディタから実行できません フォームの回答を送信してください'); 50 return; 51 } 52 53 // 製品名の質問への回答(6番目: itemResponse[5])を取得 54 const formResponse = e.response; 55 const itemResponses = formResponse.getItemResponses(); 56 const product = itemResponses[5].getResponse(); 57 58 // プロパティサービスに保存した予約済みの選択肢の配列を取得 59 const properties = PropertiesService.getDocumentProperties(); 60 let selectedTimes = properties.getProperty(product); 61 selectedTimes = selectedTimes ? JSON.parse(selectedTimes) : []; 62 63 // フォームから各質問項目を取得 64 const form = e.source; 65 const items = form.getItems(); 66 67 // 回答の製品名のセクション区切りのインデックスを取得 68 const sectionIndex = getProductSectionIndex_(product, items); 69 if (sectionIndex > 0 && sectionIndex < items.length - 1) { 70 // セクション区切りの次のインデックス 71 const itemIndex = sectionIndex + 1; 72 73 // 製品のセクションの回答(選択された値)を取得 74 if (itemIndex < items.length) { 75 const item = items[itemIndex]; 76 const responseIndex = getResponceItemIndex_(itemResponses, item); 77 78 // 選択肢から回答のあったものを除外 79 if (item && item.getType() === FormApp.ItemType.MULTIPLE_CHOICE) { 80 const meetingTime = itemResponses[responseIndex].getResponse(); 81 selectedTimes.push(meetingTime); 82 properties.setProperty(product, JSON.stringify(selectedTimes)); 83 updateMeetingTimeChoices_(item, selectedTimes); 84 } 85 } 86 } 87} 88 89function getResponceItemIndex_(itemResponses, item) { 90 // すべての回答から質問項目のIDが一致するものを取得する 91 for (let i = 0; i < itemResponses.length; i++) { 92 const responseItemId = itemResponses[i].getItem().getId(); 93 const itemId = item.getId(); 94 if (responseItemId === itemId) { 95 return i; 96 } 97 } 98 return -1; 99} 100 101function getProductSectionIndex_(product, items) { 102 // 製品名: セクションのタイトル 103 const productSections = { 104 "製品A": "製品A", 105 "製品B": "製品B", 106 "製品C": "製品C", 107 "製品D": "製品D", 108 "製品E": "製品E", 109 "製品F": "製品F" 110 }; 111 112 // 選択された製品に一致するセクションを検索 113 for (let i = 0; i < items.length; i++) { 114 if (items[i].getType() === FormApp.ItemType.PAGE_BREAK && 115 items[i].getTitle() === productSections[product]) { 116 return i; 117 } 118 } 119 return -1; 120} 121 122function updateMeetingTimeChoices_(sectionItem, selectedTimes) { 123 // 回答後の遷移先 124 const toSubmit = FormApp.PageNavigationType.SUBMIT; 125 const toStart = FormApp.PageNavigationType.RESTART; 126 127 if (sectionItem && sectionItem.getType() === FormApp.ItemType.MULTIPLE_CHOICE) { 128 // 選択肢の初期値 129 const originalChoices = [ 130 "13日(木) 10時~", 131 "13日(木) 11時~", 132 "13日(木) 13時~", 133 "13日(木) 14時~", 134 "14日(金) 10時~", 135 "14日(金) 11時~", 136 "14日(金) 13時~", 137 "14日(金) 14時~", 138 ]; 139 140 // 予約されていない選択肢を抽出 141 const availableChoices = originalChoices.filter(function (choice) { 142 return selectedTimes.indexOf(choice) === -1; 143 }); 144 145 // 抽出した選択肢(すべて予約済みならその旨)を生成 146 const choices = availableChoices.length > 0 ? 147 availableChoices.map(v => sectionItem.asMultipleChoiceItem().createChoice(v, toSubmit)) : 148 [sectionItem.asMultipleChoiceItem().createChoice('この製品はすべて予約済みです', toStart)]; 149 150 // 生成した選択肢を質問項目にセット 151 sectionItem.asMultipleChoiceItem().setChoices(choices); 152 } 153}

投稿2025/02/01 00:51

編集2025/02/01 01:27
YellowGreen

総合スコア861

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syababa

2025/02/04 04:37

お世話になります。 お返事ありがとうございます。 頂いたコードで無事動作する事が出来ました。 当方まだまだ勉強不足の為、全てを理解する事は出来ませんでしたが、 頂いたコードを基にもっと勉強してみます・・・。 ご指摘頂いております通り、キャンセルや時間の追加等は対応出来ておりませんが、 小規模展示会の技術相談で使用する予定ですので、手動で対応を予定しております。 この度は誠にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問