Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 Points

Add another form in inlineformset with javascript.

In last project I used Circle (which was in https://github.com/treehouse/circle) but seems to be deleted now.

There is a nice JavaScript function which clones (adds another) <li></li> to <ol></ol> or <ul></ul>.

Here it is:

//Cloner for infinite input lists
$(".circle--clone--list").on("click", ".circle--clone--add", function(){
var parent = $(this).parent("li");
var copy = parent.clone();
parent.after(copy);
copy.find("input, textarea, select").val("");
copy.find("*:first-child").focus();
});

$(".circle--clone--list").on("click", "li:not(:only-child) .circle--clone--remove", function(){
var parent = $(this).parent("li");
parent.remove();
});

The aim is: I want to use this function to add another form to inlineformset. Like this:

<ul class="circle--clone--list">
    {{ skill_form.management_form }}
    {{ skill_form.non_form_errors }}
    {% for form in skill_form %}
        <li>
            {{ form.id }}
            {{ form.skill }}
            <label style="display: inline; margin-right: 1em" for="id_{{ form.prefix }}-DELETE"><a>Delete</a></label>{{ form.DELETE }}<br>
            <a  class="circle--clone--add" >Add More</a>
        </li>
    {% endfor %}
</ul>

The problem is: The function CLONES <li></li>, which means new form overrides old one. And I need new form.id to be incremented (or something like that) in each new <li></li>. How to modificate the function to use it this way?

Django docs say: It is used to keep track of how many form instances are being displayed. If you are adding new forms via JavaScript, you should increment the count fields in this form as well. On the other hand, if you are using JavaScript to allow deletion of existing objects, then you need to ensure the ones being removed are properly marked for deletion by including form-#-DELETE in the POST data. It is expected that all forms are present in the POST data regardless.

Kenneth Love please, take a look at this?

1 Answer

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

This looks like maybe a good solution? It's a tricky area, for sure. If I remember correctly, in the past, I've always made sure there was a blank instance at the end of the list of inlines. I'd clone that one into JavaScript DOM objects and then just plop them in each time I needed a new instance. Gotta update that management form, too.

Alx Ki
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alx Ki
Python Web Development Techdegree Graduate 14,822 Points

It's really tricky! Took even more time to make it look nice:

project_form is an inlineformset.

<form>
#  ------------ Here is some form -----------------
        <div class="circle--secondary--module">
            <h4>My Projects</h4>
            {% load formset_tags %}
            {{ project_form.media }}
            <div id="formset2" data-formset-prefix="{{ project_form.prefix }}">
                {{ project_form.management_form }}
                <div data-formset-body>
                    <!-- New forms will be inserted in here -->
                    {% for form in project_form %}
                        <div data-formset-form>
                            {{ form.id }}
                            {{ form.name }}
                            {{ form.url }}
                            {{ form.DELETE|add_style:"display: none" }}
                            <a class="button button-text" style="padding: 0.3em" data-formset-delete-button>Remove</a>
                        </div>

                    {% endfor %}
                </div>
                <!-- The empty form template. By wrapping this in a <script> tag, the
                __prefix__ placeholder can easily be replaced in both attributes and
                any scripts -->
                <script type="form-template" data-formset-empty-form>
                    {% escapescript %}
                        <div data-formset-form>
                            {{ project_form.empty_form.id }}
                            {{ project_form.empty_form.name }}
                            {{ project_form.empty_form.url }}
                            {{ project_form.empty_form.DELETE|add_style:"display: none" }}
                        <a class="button button-text" style="padding: 0.3em" data-formset-delete-button>Remove</a>
                        </div>
                    {% endescapescript %}
                </script>
                <!-- This button will add a new form when clicked -->
                <a class="button button-text" style="padding: 0.3em" data-formset-add>Add another</a>
                <script>jQuery(function($) {
                    $("#formset2").formset({
                        animateForms: true
                    });
                });</script>
            </div>
        </div>
</form>

Another moment is: the script is not "universal" if you add more formsets to your form - you have to also change the div's id and #formset2 here:

jQuery(function($) {
$("#formset2").formset({
animateForms: true
});
});