今までの記事一覧
Googleフォーム×GASで実現する業務自動化シリーズ全記事まとめ目次
前提
この記事は、フォーム回答を保存しているスプレッドシート側のGASを前提にしています。
トリガーは以下を設定してください。
- 実行する関数:
onFormSubmit - イベントのソース:スプレッドシートから
- イベントの種類:フォーム送信時
スプレッドシート構成
スプレッドシート「集計シート」をこの図のように設定しています。
- B1セルに残数が入る
- 4行目以下にフォームから送信された注文内容が記録される
おさらい
前回はフォーム送信時に残り在庫をカウントし、フォーム上に「残り〇個」を表示するコードを作りました。
しかし「残り3個」と書いてあるのにあえて「5個」と入力して送信ボタンを押してしまう猛者が登場。残数がマイナスになり現場がパニックに。
そこで今回は、ユーザーの入力ミスをシステムでブロックする処理を実装します。
やりたいこと
フォームの「回答の検証」機能を使います。
「回答の検証」とは、この図のように「フォームの質問欄の右下の三点メニュー(︙)」 → 「回答の検証」を選択することで、回答の内容にルールを設定し、条件に合わない回答を送信できなくする機能です。

GASを使ってこれを「数値・1以上・残数以下」に設定するのが今日のミッションです。
今回使うメソッドはコレ!
-
FormApp.createTextValidation()
記述式の質問専用のバリデーション(検証ルール)の設計図を作成します。 -
.requireNumberBetween(start, end)
指定した数値の範囲内(start以上end以下)の入力のみを許可します。 -
.setHelpText(text)
このルールに反した入力をしたときに表示するメッセージを設定します。 -
.build()
組み立てたルールを確定させ、適用可能なオブジェクトに変換します。これを忘れると動きません。 -
textItem.setValidation(validation)
確定したルールを質問欄に装着。もともとルールがあったとしても、自動的に最新のルールへ上書き(更新)されます。
スプレッドシートの入力規則を作る時は SpreadsheetApp.newDataValidation() のように new〜 というメソッドを使いますが、Googleフォームの場合は FormApp.newTextValidation() ではなく FormApp.createTextValidation() になります。私もハマった間違いやすいポイントです・・・
ここを変える
まずは上記のメソッドを組み立てます。
const validation = FormApp.createTextValidation()
.setHelpText(`一度に注文できるのは ${newRemaining} 個までです。`)
.requireNumberBetween(1, newRemaining)
.build();
// 質問欄にルールを適用(古いルールは自動で上書きされます)
textItem.setValidation(validation);
これを入れるのは、前回作ったelse(残数がまだある場合)の中、item.asTextItem().setHelpText("※現在の残り在庫は・・・の下に入れます。
item.asTextItem()を定数textItem に格納しておくといいでしょう。
elseの中をこのように変えます。
// 残数がまだある場合
} else {
// フォーム全体の「説明欄」を書き換える場合
form.setDescription("【現在の残り在庫: " + newRemaining + " 個】");
// 特定の質問(注文数)の「説明欄」を書き換え、さらに入力制限もかける
const items = form.getItems();
for (const item of items) {
if (item.getTitle() === "注文数を入力してください") {
const textItem = item.asTextItem();
// ヘルプテキスト(説明文)を更新
textItem.setHelpText("※現在の残り在庫は「あと " + newRemaining + " 個」です。");
// 【今回の新機能★】「1以上、newRemaining以下」の数値しか入力できないルールを作る
const validation = FormApp.createTextValidation()
.setHelpText(`一度に注文できるのは ${newRemaining} 個までです。`)
.requireNumberBetween(1, newRemaining)
.build();
// 質問欄にルールを適用(古いルールは自動で上書きされます)
textItem.setValidation(validation);
break;
}
}
}
動作確認
まずはスプレッドシートの残数を10に戻して、フォームから「3個」を送信してみましょう。

再度、フォームを開いてみます。
残りは7個になっていますね。

赤字でアラートが出て、送信できません。
しっかりとシステムがブロックしてくれています。
フォームの管理画面で「回答の検証」を確認してみるとこのように変わっています。

これで、フォーム上で「あと〇個」が確認できるだけでなく、それ以上の数字をブロックすることができるようになりました。
フォームが「ただデータを記録するもの」から「不正な入力を防ぐ安全なシステム」へランクアップした瞬間です。
まとめ
今回は、フォームの「回答の検証」機能をGASで操作し、残数を超える送信をブロックする機能を作りました。
コード全体はこちらです。
今回の成果コード
function onFormSubmit(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = e.range.getSheet(); //フォーム回答が入力されたシート
const row = e.range.getRow(); //フォーム回答が入力された行
const column = e.values.length; // 質問の列数を取得(イベントオブジェクトから取得)
const formData = sheet.getRange(row, 1, 1, column).getValues().flat();
const sheet_summary = ss.getSheetByName("集計シート");
// フォームの回答から「注文数」を取得(文字列になるケースがあるため念のため数値化)
// formDataの中の4番目(インデックス [3] )を取得
const orderCount = Number(formData[3]);
// 「集計シート」のB1セルから現在の残数を読み込む
const currentRemaining = Number(sheet_summary.getRange("B1").getValue());
// 新しい残数を計算して、B1セルに上書き
const newRemaining = Number(currentRemaining) - orderCount;
sheet_summary.getRange("B1").setValue(newRemaining);
//まとめシートに転記
sheet_summary.getRange(sheet_summary.getLastRow() + 1, 1, 1, column).setValues([formData]);
//紐づいているフォームを取得
const formUrl = ss.getFormUrl(); // スプレッドシートに紐づくフォームのURLを取得
const form = FormApp.openByUrl(formUrl);
// もし残数が0以下になったら、フォームを自動で締め切る
if (newRemaining <= 0) {
form.setCustomClosedFormMessage("本日の注文受付は【完売】のため終了いたしました。またのご利用をお待ちしております!");
form.setAcceptingResponses(false); // 新規受付を停止
} else { //残数がまだある場合
//フォーム全体の「説明欄」を書き換える場合
form.setDescription("【現在の残り在庫: " + newRemaining + " 個】");
//特定の質問(注文数)の「説明欄」を書き換える場合
const items = form.getItems();
for (const item of items) {
// 質問のタイトルが「注文数を入力してください」の項目を探す
if (item.getTitle() === "注文数を入力してください") {
// TextItem(記述式)に型変換して変数に格納
const textItem = item.asTextItem();
// ヘルプテキスト(説明欄)を更新
textItem.setHelpText("※現在の残り在庫は「あと " + newRemaining + " 個」です。");
// 【今回の新機能】検証ルールを組み立てる
const validation = FormApp.createTextValidation()
.setHelpText(`一度に注文できるのは ${newRemaining} 個までです。`)
.requireNumberBetween(1, newRemaining)
.build();
// 質問欄にルールを適用(古いルールは自動で上書きされます)
textItem.setValidation(validation);
break;
}
}
}
}
Googleフォーム標準の「回答の検証」では、「整数のみ」と「〇以上〇以下」は同時に設定できません。
そのため今回は 「残数を超える注文を防ぐこと」 を優先し、入力範囲の制限を採用 しています。
この方法では 3.5 のような小数は入力できてしまいますが、「1個しか残っていないのに5個注文する」といった大きな入力ミスは防げます。
整数制限と範囲制限を同時に行いたい場合は、正規表現や別ロジックでの実装が必要になり、少し複雑になります。
次回は別アプローチ。
そもそも注文数を自由入力(記述式)にしているから残数オーバーや小数問題が起こるんですよね。
そこで次回は、「プルダウン」や「ラジオボタン」に変更し、選択肢の候補そのものを現在の残数に応じて動的に書き換える方法を試してみようと思います。
入力ミスを後から防ぐのではなく、そもそもミスが起きないUI を作ってみましょう。
次回はこちら
Googleフォーム×在庫管理!プルダウン/ラジオボタンを動的変更して残数超過を防ぐ




