Skip to content

Instantly share code, notes, and snippets.

@ttsukagoshi
Last active January 17, 2023 00:12
Show Gist options
  • Save ttsukagoshi/124934bf08687c5c916cee3e89c6a91e to your computer and use it in GitHub Desktop.
Save ttsukagoshi/124934bf08687c5c916cee3e89c6a91e to your computer and use it in GitHub Desktop.
Googleフォームで、選択肢ごとに定員を設定して、定員に達したらその選択肢を非表示にするためのGoogle Apps Script。 https://gist.github.com/ttsukagoshi/d9fad5b8865066ddefa64be9cff208d0 の後継。
{
"timeZone": "Asia/Tokyo",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/forms",
"https://www.googleapis.com/auth/script.send_mail",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/userinfo.email"
],
"runtimeVersion": "V8"
}
const SHEET_NAME_CONFIG = '01_設定'; // 設定シート名
/**
* onFormSubmitを手動でも実行できるように、スプレッドシートにメニューとして設定
*/
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('定員付き選択肢')
.addItem('選択肢設定(手動)', 'onFormSubmit')
.addToUi();
}
/**
* 対象の設問について、既存の回答の集計数が定員に達していない選択肢のみを選択肢として設定する。
* この関数が「フォーム送信時」のトリガーで実行されるように設定しておく。
*/
function onFormSubmit() {
const config = getConfig_(); // 設定値を取得
const ss = SpreadsheetApp.getActiveSpreadsheet(); // 本スプレッドシート
const targetForm = FormApp.openById(config.FORM_ID); // 対象Googleフォーム
try {
// 選択肢とその定員を取得
let choicesPre = ss.getSheetByName(config.SHEET_NAME_CHOICES)
.getDataRange()
.getValues();
const choicesHeader = choicesPre.shift();
const choices = choicesPre.map((row) => choicesHeader.reduce((o, k, i) => {
o[k] = row[i];
return o;
}, {}));
// 既存の回答を取得し、対象の設問について選択肢別の回答数を集計
let responsesPre = ss.getSheetByName(config.SHEET_NAME_RESPONSES)
.getDataRange()
.getValues();
const responsesHeader = responsesPre.shift();
const responsesTargetItemIndex = responsesHeader.findIndex(element => element === config.TARGET_ITEM_NAME);
if (responsesTargetItemIndex === -1) {
throw new Error(`設問「${config.TARGET_ITEM_NAME}」は存在しないようです。シート「${SHEET_NAME_CONFIG}」で、選択肢ごとの定員を設ける設問の「質問」部分で入力した文字列が正しく設定されていることを確認してください。`);
}
const responsesCount = responsesPre.reduce((countObj, responseRow) => {
if (!countObj[responseRow[responsesTargetItemIndex]]) {
countObj[responseRow[responsesTargetItemIndex]] = 0;
}
countObj[responseRow[responsesTargetItemIndex]] += 1;
return countObj;
}, {});
// 選択肢として残すものを絞り込む
const choicesFiltered = choices.reduce((filteredArr, choice) => {
if (!responsesCount[choice['選択肢']] || responsesCount[choice['選択肢']] < choice['定員']) {
filteredArr.push(choice['選択肢']);
}
return filteredArr;
}, []);
if (choicesFiltered.length > 0) {
// フォームの回答を受け付ける
targetForm.setAcceptingResponses(true);
// Googleフォームの対象設問に選択肢を設定し直す
targetForm.getItems().forEach(item => {
if (item.getTitle() === config.TARGET_ITEM_NAME) {
const itemType = item.getType();
if (itemType !== FormApp.ItemType.MULTIPLE_CHOICE &&
itemType !== FormApp.ItemType.LIST) {
throw new Error(`対象設問はラジオボタンまたはプルダウンでなければいけません。`);
}
const targetItem = itemType === FormApp.ItemType.MULTIPLE_CHOICE
? item.asMultipleChoiceItem()
: item.asListItem();
targetItem.setChoiceValues(choicesFiltered);
}
});
} else {
// 満員につき、回答受付終了
targetForm.setAcceptingResponses(false);
}
} catch (error) {
MailApp.sendEmail(
Session.getActiveUser().getEmail(),
`[ERROR] フォーム「${ss.getName()}」での選択肢設定エラー`,
error.stack);
console.error(error.stack);
}
}
/**
* 設定シートの値を、A列の値をkeyに、B列を値をvalueとしたオブジェクトに変換する。
* @return {*}
*/
function getConfig_() {
const configPre = SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName(SHEET_NAME_CONFIG)
.getDataRange()
.getValues();
configPre.shift();
return configPre.reduce((configObj, row) => {
configObj[row[0]] = row[1];
return configObj;
}, {});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment