JqueryでHTMLを流動的に書き換えることはよくあります。
実際にエラーメッセージ等を出力する場合等に重宝します。
今回、JqueryでHTMLの書き換えを実装することになったのですが、書き換えるのはSELECTフォームの選択肢です。
具体的には、SELECTフォームが2つあり、一つ目の選択内容によって、2つ目のSELECTフォームの選択肢を変化させるというものです。
EC-CUBEでよくあるやつです。
やればできることですが、どうやればいいの?
状態でした。
いろいろググり、試行錯誤して実装できましたので、忘備録として記録いたします。
今回やりたいこと
サンプルを見ていただければ一目瞭然ですが、大項目の選択によって、小項目の選択肢が変化します。
今回のソースはこちら
<!doctype html>
<html>
<head>
<meta charset="shift_jis">
<title>セレクトで値を切り替える</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function()
{
// (2)選択肢テーブル
// 色テーブル
var color_table =
[
{value: "red", label: "赤"},
{value: "blue", label: "青"},
{value: "yellow", label: "黄"},
{value: "pink", label: "桃"},
{value: "green", label: "緑"}
]
// サイズテーブル
var size_table =
[
{value: "small", label: "小さい"},
{value: "normal", label: "普通"},
{value: "big", label: "大きい"}
]
// (3)大項目が変化した場合に発火
$("[name=syubetu]").change(function()
{
// 選択した値を取得
var select_value = $(this).val();
// (4)現在の小項目を初期化
// 2番目のセレクトを初期化
$("[name=sub]").children().remove();
if (select_value == 1) // 色指定 ?
{
// (5)選択肢をセット
// 色テーブルをセット
color_table.forEach( function(table)
{
$("[name=sub]").append($("<option>").attr({ value: table.value}).text(table.label));
});
}
else if (select_value == 2) // サイズ指定
{
// サイズテーブルをセット
size_table.forEach( function(table)
{
$("[name=sub]").append($("<option>").attr({ value: table.value}).text(table.label));
});
}
});
});
</script>
<style type="text/css">
.box
{
padding: 20px;
width: 400px;
margin-right: auto;
margin-left: auto;
}
section
{
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
}
p
{
margin: 0px;
}
select
{
font-size: 18px;
padding: 10px;
}
</style>
</head>
<body>
<div class="box">
<p>大項目を選択すると小項目の値が変わります</p>
<!-- (1)SELECTフォーム部分 -->
<section>
<p>大項目</p>
<select name="syubetu">
<option value="">大項目を選択してください</option>
<option value="1">色</option>
<option value="2">大きさ</option>
</select>
</section>
<section>
<p>小項目</p>
<select name="sub">
</select>
</section>
</div>
</body>
</html>
例のごとくまとめてみると何のことかわからないので、分解して考えます。
(1)SELECTフォーム部分
<section>
<p>大項目</p>
<select name="syubetu">
<option value="">大項目を選択してください</option>
<option value="1">色</option>
<option value="2">大きさ</option>
</select>
</section>
<section>
<p>小項目</p>
<select name="sub">
</select>
</section>
セレクトフォーム部分は、通常の記載と同じです。
違う部分は、小項目の選択肢(option)が1つも記述がありません。
これは、Jqueryで後から付け足すため記述する必要がないのです。
(2)選択肢テーブル部分
// 色テーブル
var color_table =
[
{value: "red", label: "赤"},
{value: "blue", label: "青"},
{value: "yellow", label: "黄"},
{value: "pink", label: "桃"},
{value: "green", label: "緑"}
]
// サイズテーブル
var size_table =
[
{value: "small", label: "小さい"},
{value: "normal", label: "普通"},
{value: "big", label: "大きい"}
]
選択肢を付け足すには、後述しますがJqueryのappend()を使用します。
ただ、汎用性を高めるため、事前に選択肢を配列化しました。
Javascriptの二次配列については、こちらをご参考ください。
(3)大項目が変化した場合に発火する部分
$("[name=syubetu]").change(function()
{
});
大項目が変化したら、小項目の内容を書き換えるので、大項目が変化したタイミングを検知しなければいけません。
それがこの部分です。
Jqueryの change()関数は、指定項目の値が変化したら発火します。
(4)現在の小項目を初期化する
// 2番目のセレクトを初期化
$("[name=sub]").children().remove();
大項目が確定したら、小項目の中身をいったんクリアする必要があります。
なぜならば、クリアしなければどんどん追加されてしまうからです。
今回は全削除ですが、個別削除も可能です。
例えば「赤」を消す場合は次のように記述します。
$("[name=sub]").children("[value=red]").remove();
(5)選択肢を追加する
// 色テーブルをセット
color_table.forEach( function(table)
{
$("[name=sub]").append($("<option>").attr({ value: table.value}).text(table.label));
});
Jqueryのappend()で小項目に選択肢を追加しています。
今回の最も肝心な部分です。
仕掛けは、(2)のテーブルをループさせ、テーブルの値の数だけ追加しています。
forEachは、配列をループさせる命令です。PHP等にはない記述方法なのでわかりにくいですが、foreach文と似ています。
appendは、タグをダイレクトに記述する方法もありますが、配列の値をセットすることを考えたら、分解してセットするやり方のほうがわかりやすかったです。
append部分は、共通で使えるためサブルーチン化してもOKです。
試しにサブルーチンかしてみたら、うまくいきました。
今回悩んだこと
今回は複数の事象についてどうすればいいのか悩みました。
それがこちらです。
- SELECTの選択肢をその都度書き換えるにはどうすればいいのか?
- その選択肢を配列化しておくことはできるのか?
- 大項目選択時に、どの小項目テーブルを使用すればよいか区別をつけることができるのか?
難問が複数同時に来ると、パニックになってしまいがちです。
なので私は今回は頭からひとつづつ問題点を解決してゆきました。
3回解決したら完成していました。
千里の道も一歩からといいますが、難問も千個に分解すれば簡単な問題の集合体です。
パニックになる前に、地道に一つずつ解決してゆくことが結果的に近道です。