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

検索フォームを追加したいとご依頼あり。
最初からたくさんフォームを出しとくのもかっこ悪いし、
とはいえ一個一個要素を増やすのもめんどくさい。
追加ボタンで動的にまるっとコピーできないかしら、ってことでやってみました。
jQueryほんとべんり。

[Add & Remove form elements dynamically](https://jsfiddle.net/Siskara/tpmgy43L/)
(2018/12/19変更：runnableがリンク切れしていたのでjsfiddleに引っ越し)

以下解説↓

#元のフォーム
これがないと始まらない。
フォーム全体をform-blockとしてくくり、idに番号0を振っておきます。
中の要素も同じ番号。増やすのはform-block単位。

```html: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`で管理。

```js:script.js
      var original = $('#form_block\\[' + frm_cnt + '\\]');
      var originCnt = frm_cnt;
      var originVal = $("input[name='sex\\[" + frm_cnt + "\\]']:checked").val();
```

`frm_cnt`をインクリメントする前にオリジナル（一つ前のフォーム）オブジェクトを取得しておく。
ラジオボタンのvalueも取っておくのは後のため。

```js: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を新しい番号に変更、テキストの値をクリア

```js:script.js
      // clone取得
      var clone = $('#form_block\\[' + frm_cnt + '\\]');
      clone.children('span.close').show();
      clone.slideDown('slow');
```

クローンができたので表示します。
クローズボタンも一緒に。

```js:script.js
      // originalラジオボタン復元
      original.find("input[name='sex\\[" + originCnt + "\\]'][value='" + originVal + "']").prop('checked', true);
```

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

#フォームの削除
フォーム内部に配置したCloseボタンを押すと、親フォームを削除します。
その後、全体的に番号の振り直しをします。
※[0]のフォームは消しません。

```js: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 + ']')
                            });
                        });
                }
            });
        });
```