【jQuery】フォームのinputを動的に追加・削除する(連番を振りなおす)
①動作サンプル(単純にinput要素を追加)
See the Pen input_add_sample1 by Cheemo (@Cheemo-LapinWeb) on CodePen.
②より実践的なサンプル
See the Pen input_add_sample2 by Cheemo (@Cheemo-LapinWeb) on CodePen.
ラベルやid、nameなどの連番を振る。(削除したら欠番を詰めて振り直し)
実際には入力値をpostしてDBへの登録処理をごにょごにょする時に連番が振られてた方が便利・振る必要がある場合もあると思うので、こんな感じで使うと思われます。
あと入力欄はいくつかがセットで増減させる場合がほとんどだと思うので、そんな感じにしています。
もくじ
単純にinput要素を追加するサンプルの解説
テキストボックスを増やしたいだけなら
$(".text_box").first().clone().val("").appendTo("form");
この一行だけでOK。
first()を指定しないと全部のinputが複製されて、ボタンを押す度に.text_boxが増えまくる倍々ゲームになってしまうので、first()によって1番目の要素だけ複製するようにしています。
また、val(“”)で入力値はコピーしないように初期化しています。指定しなければ入力中のテキストも同じように複製されます。
削除ボタンは.text_boxが2つ以上ある場合にのみ有効化。
※1つもなくなってしまうとclone()する元の要素がなくなってしまうため。
削除ボタンを押したら一番最後の.text_boxが削除されます。
実践的なサンプルの解説
コードを見る
//サンプル②
//追加ボタンを押すと行が追加される
//ラベル、id、nameに連番が振られる
//削除ボタンを押すとその行が削除される
//空いた連番を詰める
//削除ボタンは行が2以上ある場合のみ表示される
$(function() {
var rownum = 1; //入力行(.item_row)をカウントする変数
//追加ボタンを押したとき
$("#addButton").on("click", function() {
rownum++;
var clone_row = $(".item_row").first().clone(true); //clone(true)にすることでクリックイベントが発火するようになる
clone_row.val("");
change_attr(clone_row, rownum); //連番を振る
clone_row.appendTo("form");
removeButton_check();
});
//削除ボタンを押したとき
$(".form_area").on("click", ".removeButton", function() {
rownum--;
$(this).parent(".item_row").remove();
var rowcount = 0;
while(rowcount <= rownum) {
var target_row = $("form").children('.item_row').eq(rowcount);
if(!(target_row.find("#item_id_" + rowcount + 1).length)) { //空き番があるかチェック
change_attr(target_row, rowcount + 1); //連番を振りなおす
}
rowcount++;
}
removeButton_check();
});
//削除ボタン有効化チェック
function removeButton_check() {
if($(".removeButton").length >= 2) {
$(".removeButton").prop("disabled", false);
} else {
$(".removeButton").prop("disabled", true);
}
}
//idやnameの連番を振る
function change_attr(target, rownum) {
target.find("label[for^='item_id_']").attr({
for: ('item_id_' + rownum)
}).text("商品" + rownum);
target.find("[id^=item_id_]").attr({
'id': ('item_id_' + rownum),
'name': ('item_id_' + rownum)
});
target.find("label[for^='price_']").attr({
for: ('price_' + rownum)
});
target.find("[id^=price_]").attr({
'id': ('price_' + rownum),
'name': ('price_' + rownum)
});
target.find("label[for^='quantity_']").attr({
for: ('quantity_' + rownum)
});
target.find("[id^=quantity_]").attr({
'id': ('quantity_' + rownum),
'name': ('quantity_' + rownum)
});
}
});
要素の追加
.item_rowでひとまとめにしたい要素を囲い、行ごとclone()して追加しています。
入力欄を追加するとラベル(商品〇〇)に連番が振られ、idとnameにもitem_id_〇〇みたいに番号が振られます。
(idとかnameはデベロッパーツールで確認してください)
生成されるHTML
<div class="form_area sample2">
<button id="addButton" type="button">追加</button>
<form action="" method="">
<div class="item_row">
<div class="form_group">
<div class="text_box">
<label for="item_id_1">商品1</label>
<input type="text" id="item_id_1" name="item_id_1">
</div>
</div>
<div class="form_group">
<div class="input_number">
<label for="price_1">単価</label>
<input type="number" id="price_1" name="price_1">
</div>
</div>
<div class="form_group">
<div class="input_number">
<label for="quantity_1">数量</label>
<input type="number" id="quantity_1" name="quantity_1">
</div>
</div>
<button class="removeButton" type="button">削除</button>
</div>
<div class="item_row">
<div class="form_group">
<div class="text_box">
<label for="item_id_2">商品2</label>
<input type="text" id="item_id_2" name="item_id_2">
</div>
</div>
<div class="form_group">
<div class="input_number">
<label for="price_2">単価</label>
<input type="number" id="price_2" name="price_2">
</div>
</div>
<div class="form_group">
<div class="input_number">
<label for="quantity_2">数量</label>
<input type="number" id="quantity_2" name="quantity_2">
</div>
</div>
<button class="removeButton" type="button">削除</button>
</div>
<div class="item_row">
・・・入力行分増える
</div>
</form>
</div>
削除は最初のサンプルのように後ろの要素からするのではなく、任意の行を削除できるようにしたかったので行ごとにボタンを配置しました。
ここでclone(true)と引数を指定しないと、複製した要素のイベントリスナーが動作しなくなってしまうので削除ボタンが動かなくなります。必ずtrueを入れましょう。
削除用クリックイベントの設定
削除用ボタンがクリックされた場合の動作は以下の通り。
最初のサンプルとは初っ端から書き方が異なります。
$(".form_area").on("click", ".removeButton", function() {
・・・
あとから追加した要素にイベントを設定させるにはポイントが2つ。
一つはonメソッドを使う必要があります。
サンプル①でもonを使ってましたが、こういう書き方だと動的に追加した要素のクリックイベントは動作しません。
$(".removeButton").click(function() {
・・・
もう一つはサンプル①のように
$(".removeButton").on("click", function() {
・・・
これでもだめで、元からあった要素を基準にイベントを設定する必要があります。
$(".form_area").on("click", ".removeButton", function() {
・・・
※$(“.form_area”) 元から存在する親要素
ちーも
bodyとかでもいいです
削除ボタンが押された後、whileで入力欄の分ループしながら抜け番を探し、抜けがあれば番号を詰めるためのメソッドを呼び出しています。
ちなみに要素の追加時に連番を振るときも同じメソッドを使っています。
連番を振る(詰める)ためのメソッド(change_attr)
attr()で属性の書き換えをしているだけです。
attr(‘id’, ‘test’); みたいな使い方をする場面が多いと思いますが、複数の属性に対して操作したい場合はこのように書くことができます。
すんごい力業なので、要素が増えてくると大変かもしれません。
おまけ(入力行の最大個数を決める場合)
removeButton_check()内に以下の記述を追加。
※入力行を最大10までに制限
//入力行の最大個数を決める場合
if(rownum >= 10) {
$("#addButton").prop("disabled", true);
} else {
$("#addButton").prop("disabled", false);
}
See the Pen input_add_sample3 by Cheemo (@Cheemo-LapinWeb) on CodePen.
10行ある場合は追加ボタンが無効化されます。
メソッド名がなんか気持ち悪くなるのでbutton_check()とかに変更した方がいいかもです。
おわりです。