Edited at

jQueryでフォームを動的に追加/削除

検索フォームを追加したいとご依頼あり。

最初からたくさんフォームを出しとくのもかっこ悪いし、

とはいえ一個一個要素を増やすのもめんどくさい。

追加ボタンで動的にまるっとコピーできないかしら、ってことでやってみました。

jQueryほんとべんり。

Add & Remove form elements dynamically

(2018/12/19変更:runnableがリンク切れしていたのでjsfiddleに引っ越し)

以下解説↓


元のフォーム

これがないと始まらない。

フォーム全体をform-blockとしてくくり、idに番号0を振っておきます。

中の要素も同じ番号。増やすのはform-block単位。


index.html

    <form method="post" action="confirm">

<div class="form-block" id="form_block[0]">
<!-- Closeボタン -->
<span class="close" title="Close" style="display: none;">-</span>

<p>Name:<input type="text" name="name[0]" id="name[0]" /></p>
<p>Sex:
<input type="radio" name="sex[0]" id="sex_male[0]" value="male" checked>male
<input type="radio" name="sex[0]" id="sex_female[0]" value="female">female
</p>
<p>Memo:<textarea name="memo[0]" id="memo[0]" rows="3"></textarea></p>
</div>

<!-- Addボタン -->
<div class="form-block" id="form_add">
<span class="add" title="Add">+</span>
</div>
</form>



フォームの追加

Addボタンを押したら、一つ上のフォームをクローンします。

現在フォーム数はグローバル変数frm_cntで管理。


script.js

      var original = $('#form_block\\[' + frm_cnt + '\\]');

var originCnt = frm_cnt;
var originVal = $("input[name='sex\\[" + frm_cnt + "\\]']:checked").val();

frm_cntをインクリメントする前にオリジナル(一つ前のフォーム)オブジェクトを取得しておく。

ラジオボタンのvalueも取っておくのは後のため。


script.js

      frm_cnt++;

original
.clone()
.hide()
.insertAfter(original)
.attr('id', 'form_block[' + frm_cnt + ']') // クローンのid属性を変更。
.find("input[type='radio'][checked]").prop('checked', true)
.end() // 一度適用する
.find('input, textarea').each(function(idx, obj) {
$(obj).attr({
id: $(obj).attr('id').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']'),
name: $(obj).attr('name').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']')
});
$(obj).val('');
});


オリジナルからクローンします。

やっていることは上から順に、

 1. クローンする

 2. 一旦隠す

 3. オリジナルの後ろに突っ込む

 4. クローンしたform_blockのidを新しい番号に変更

 5. ラジオボタンのデフォルト値を設定

 6. 上記を一旦適用

 7. text及びtextareaのidとnameを新しい番号に変更、テキストの値をクリア


script.js

      // clone取得

var clone = $('#form_block\\[' + frm_cnt + '\\]');
clone.children('span.close').show();
clone.slideDown('slow');

クローンができたので表示します。

クローズボタンも一緒に。


script.js

      // originalラジオボタン復元

original.find("input[name='sex\\[" + originCnt + "\\]'][value='" + originVal + "']").prop('checked', true);

で、これ。

クローンしたとき、オリジナルのラジオボタンのチェックが消えてしまうんですよね。

なのでここで戻しています。


フォームの削除

フォーム内部に配置したCloseボタンを押すと、親フォームを削除します。

その後、全体的に番号の振り直しをします。

※[0]のフォームは消しません。


script.js

        var removeObj = $(this).parent();

removeObj.fadeOut('fast', function() {
removeObj.remove();
// 番号振り直し
frm_cnt = 0;
$(".form-block[id^='form_block']").each(function(index, formObj) {
if ($(formObj).attr('id') != 'form_block[0]') {
frm_cnt++;
$(formObj)
.attr('id', 'form_block[' + frm_cnt + ']') // id属性を変更。
.find('input, textarea').each(function(idx, obj) {
$(obj).attr({
id: $(obj).attr('id').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']'),
name: $(obj).attr('name').replace(/\[[0-9]\]+$/, '[' + frm_cnt + ']')
});
});
}
});
});