[Fixed]-Add a dynamic form to a django formset using javascript in a right way


This self-answer is based on this post by Nick Lang, but we are going to simplify this way and we don’t need to copy/paste whole form html anymore.

We have an inline formset which is created in a view like this:

items_formset = inlineformset_factory(Parent, Item, form=ItemForm, extra=1)
item_forms = items_formset()  

Next, we need to create a template for out formset form, we can do it using empty_form property of formset instance, which generates a html form template where every “id” number of a form is replaced by __prefix__ string, for example:

{{ item_forms.empty_form }}

{# <!-- or for crispy forms --> {% crispy item_forms.empty_form item_forms.form.helper %} #}

So, first we need to replace this __prefix__ by an id and add a form using this template.
Here is a form template code fragment, which we can use to create new elements:

<script type="text/html" id="item-template">
<div id="item-__prefix__">
    {{ item_forms.empty_form }}
    <!-- crispy: {% crispy item_forms.empty_form item_forms.form.helper %} -->

Then we need to display main part of the form:

<form action="" method="post">
{% csrf_token %}
{{ item_forms.management_form }}
<div id="items-form-container">
    {% for item_form in item_forms %}
        <div id="item-{{ forloop.counter0 }}">
            {{ item_form.id }}
            {{ item_form.as_p }}
            {# <!-- or for crispy forms --> {% crispy item_form %} #}
    {% endfor %}
<a href="#" id="add-item-button" class="btn btn-info add-item">Add Item</a>

Finally we need to add some JS (jquery, tested with 1.9.1 and 2.1.0) to add a next formset form. Note we will not use underscore.js, since it’s unneeded in this case: just str.replace to replace __prefix__ by next “id” number)

$(document).ready(function() {
    $('.add-item').click(function(ev) {
        var count = $('#items-form-container').children().length;
        var tmplMarkup = $('#item-template').html();
        var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);

        // update form count
        $('#id_item_items-TOTAL_FORMS').attr('value', count+1);

        // some animate to scroll to view our new form
        $('html, body').animate({
                scrollTop: $("#add-item-button").position().top-200
            }, 800);

That’s all, just click on “Add Item” button, and a new formset item will appear.

Be sure to replace this sample by your app_name/model_name.


Leave a comment