はじめに
独学でプログラミングを学習中の大学3年生です。
以前、WebアプリケーションをPHPで作成したときにフォームの入力欄を動的に追加したことがありました。現在、WebアプリをDjangoに移行中なのですが、タイトルの問題に当たってなかなか解決しなかったためここに残しておきます。
ドキュメントにはこれしか書かれてなかった…
(2020/08/26 追記: ここにちゃんと書かれてました笑)
empty_form
BaseFormSet provides an additional attribute empty_form which returns a form instance with a prefix of prefix for easier use in dynamic forms with JavaScript.
初学者にも分かりやすいように、できるだけ簡潔なコードになるよう心がけています。
以前の記事
この記事だけで分からないときは、以前の記事を見てもらえると分かるかもしれません。
- フォームの入力欄を動的に追加する
- CodePen(動作を確認できます。)
コード
Djangoでフォームを動的に扱う場合には、Formsetsのempty_formを使います。
Djangoが生成する一般的なフォームのinput
には、id_form-{No.}-place_name
のようなidが自動で挿入されます。ただし、empty_formを使った場合はすべてのinput
のidがid_form-__plefix__-place_name
となるため、__plefix__
の部分を数字に書き換える必要があります。
<form method="POST" id="form">
{% csrf_token %}
{{ form.management_form }}
<div class="text">
{{ form.empty_form.as_p }}
</div>
<button type="button" id="btn-clone">clone</button>
<button type="submit">submit</button>
</form>
実際には、このように表示されます。
<form method="POST" id="form">
<!-- ...... -->
<input type="hidden" name="form-TOTAL_FORMS" value="2" id="id_form-TOTAL_FORMS">
<!-- ...... -->
<div class="text">
<p>
<label for="id_form-__prefix__-place_name">Input:</label>
<input type="text" name="form-__prefix__-place_name" id="id_form-__prefix__-place_name">
<input type="hidden" name="form-__prefix__-id" id="id_form-__prefix__-id">
</p>
</div>
<button type="button" id="btn-clone">clone</button>
<button type="submit">submit</button>
</form>
__prefix__
を書き換えます。
また、input[id="id_form-TOTAL_FORMS"]
のvalueでinput
の数を指定します。
$(function() {
// clone
$('#btn-clone').click(function() {
var text = $('.text').last(); // 最後尾にあるinput
clone = text.clone().insertAfter(text); // inputを最後尾に追加
clone.find("input[type='text']").val(''); // valueもクローンされるので削除する
});
// ここからDjango用のidなどを操作する
$('#form').submit(function() { // フォームを送信する直前
// フォームの入力欄の数を指定する
const text = $('.text');
$('[name=form-TOTAL_FORMS]').val(text.length);
// それぞれの入力欄の__prefix__をindexで置換する
text.each(function(index, element){
html = $(element).html().replace(/__prefix__/g, index);
value = $(element).find("input[type='text']").val(); // valueが消えるので保存しておく
$(element).html(html);
$(element).find("input[type='text']").val(value);
});
});
});
フォームの削除機能を実装したい場合は、以前の記事をご覧ください。ここでは見やすいようにフォームの追加だけを実装しています。なお、最終的にフォームの削除機能の実装を想定しているため、コードが冗長になっています。フォームの削除機能が必要ない場合は修正してください。