Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Created December 8, 2025 06:47
Show Gist options
  • Select an option

  • Save kobitoDevelopment/77e4124831209ba73c4f10882d76ce28 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/77e4124831209ba73c4f10882d76ce28 to your computer and use it in GitHub Desktop.
/*
購入制限フロー:
1. フォーム送信イベントが発生
2. FormDataオブジェクトからすべての商品の購入数量を取得
3. 購入数量制限チェック(validateQuantity):
- 各商品のmaxQuantityと比較
- -1は無制限、それ以外は上限値
- 上限超過時はエラーメッセージ生成
4. 同時購入不可組み合わせチェック(validateCombination):
- incompatibleProducts配列の各ペアをチェック
- 両方とも1個以上購入予定の場合はエラーメッセージ生成
5. 全エラーメッセージをconsole.logで出力
6. エラーなしの場合は「購入可能です」を出力
*/
// デフォルトの購入可能数
const DEFAULT_PURCHASE_LIMIT = 2;
// 各商品情報
const productConfig = {
productA: { name: "商品A", maxQuantity: DEFAULT_PURCHASE_LIMIT },
productB: { name: "商品B", maxQuantity: -1 },
productC: { name: "商品C", maxQuantity: 5 },
productD: { name: "商品D", maxQuantity: DEFAULT_PURCHASE_LIMIT },
productE: { name: "商品E", maxQuantity: DEFAULT_PURCHASE_LIMIT },
};
// 同時に購入できない組み合わせ
const incompatibleProducts = [
["productA", "productB"],
["productC", "productD"],
];
/**
* 各商品の購入数量が上限を超えていないかをチェックする
* @param {Object.<string, number>} purchaseQuantities - 商品名をキーとした購入数量のオブジェクト
* @returns {string[]} エラーメッセージの配列
*/
function validateQuantity(purchaseQuantities) {
// エラーメッセージを格納する配列を初期化
const errors = [];
// 全商品について数量制限をチェック
for (const productName in productConfig) {
// productConfigオブジェクトから商品名をキーとして該当商品のオブジェクトを取得
const config = productConfig[productName];
// purchaseQuantitiesオブジェクトから商品名をキーとして購入数量の数値を取得
const quantity = purchaseQuantities[productName];
// 無制限でない場合(-1以外)かつ上限を超えている場合
if (config.maxQuantity !== -1 && quantity > config.maxQuantity) {
// エラー文字列を作成してerrors配列の末尾に追加
errors.push(`${productName}は${config.maxQuantity + "個まで"}です`);
}
}
// エラーメッセージの配列を返す
return errors;
}
/**
* 同時購入不可の商品組み合わせをチェックする
* @param {Object.<string, number>} purchaseQuantities - 商品名をキーとした購入数量のオブジェクト
* @returns {string[]} エラーメッセージの配列
*/
function validateCombination(purchaseQuantities) {
// エラーメッセージを格納する配列を初期化
const errors = [];
// 同時購入不可の商品ペアを順次チェック
for (const incompatiblePair of incompatibleProducts) {
// 配列の1番目と2番目の要素を分割代入でそれぞれ別の変数に代入
const [product1, product2] = incompatiblePair;
// 両方の商品が1個以上購入予定の場合
if (purchaseQuantities[product1] > 0 && purchaseQuantities[product2] > 0) {
// テンプレートリテラルでエラー文字列を作成してerrors配列の末尾に追加
errors.push(`${product1}と${product2}は同時に購入できません`);
}
}
// エラーメッセージの配列を返す
return errors;
}
/**
* フォームデータから購入バリデーションを実行する
* @param {FormData} purchaseFormData - 購入フォームのFormDataオブジェクト
* @returns {string[]} エラーメッセージの配列
*/
function validatePurchase(purchaseFormData) {
// 各商品の購入数量を格納するオブジェクトを初期化
const purchaseQuantities = {};
// 全商品についてフォームデータから購入数量を取得
for (const productName in productConfig) {
// FormDataから値を取得してparseIntで整数変換、NaNの場合は論理OR演算子で0を代入
purchaseQuantities[productName] = parseInt(purchaseFormData.get(productName)) || 0;
}
// validateQuantity関数を呼び出して戻り値の配列をquantityErrors変数に代入
const quantityErrors = validateQuantity(purchaseQuantities);
// validateCombination関数を呼び出して戻り値の配列をcombinationErrors変数に代入
const combinationErrors = validateCombination(purchaseQuantities);
// スプレッド構文で2つの配列を展開して新しい配列を作成してreturn
return [...quantityErrors, ...combinationErrors];
}
document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("purchaseForm");
form.addEventListener("submit", (e) => {
e.preventDefault();
const formData = new FormData(form);
const errors = validatePurchase(formData);
if (errors.length > 0) {
errors.forEach((error) => console.log(error));
} else {
console.log("購入可能です");
}
});
});
<form id="purchaseForm">
<div>
<label>商品A: <input type="number" name="productA" min="0" value="0" /></label>
</div>
<div>
<label>商品B: <input type="number" name="productB" min="0" value="0" /></label>
</div>
<div>
<label>商品C: <input type="number" name="productC" min="0" value="0" /></label>
</div>
<div>
<label>商品D: <input type="number" name="productD" min="0" value="0" /></label>
</div>
<div>
<label>商品E: <input type="number" name="productE" min="0" value="0" /></label>
</div>
<button type="submit">購入確認</button>
</form>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment