简体   繁体   中英

Dynamically Add Form to Django Formset

I want to dynamically add a form to my Django formset. However, on button click nothing happens. I am using form models, but I am defining most elements within the template. I know this is not proper practice, but it was how I originally created my forms and I have not had time to migrate to complete form models. However, could this be causing my issues? I have never used formsets before so any tips would be greatly appreciated! I used Dave's solution here , but I am unsure as to why my implementation does not translate accordingly.

template.html

<div class="container">
    <div id="form_set">
        <form action="{% url 'presales' %}" class="presales_formset" data-total-url="{% url 'presales_total' %}" id="presalesForm"method="post" name="presalesForm">
            <div class="field">
                <label class="label is-large">High Level Task List</label>
            </div>
            {% csrf_token %}

            {{ presales_formset.management_form }}

            {% for presales_form in presales_formset %}
                <div class="section">
                    <div class="field">
                        <label class="label">Opportunity</label>
                        <div class="select">
                            <select id="select_opportunity" name="select_opportunity">
                                <option value="">Opportunity</option>
                                {% for opportunity in my_opportunities %}
                                    <option id="selected_opportunity" name="selected_opportunity" value="{{ opportunity.name }}">{{ opportunity.name }}</option>
                                {% endfor %}
                            </select>
                        </div>
                    </div>
                    <label class="label">Task Description:</label>
                    <div class="field">
                        <div class="control">
                            <input class="input" id="task_description" name="task_description" placeholder="Task Description">
                        </div>
                    </div>
                    <label class="label">Hours</label>
                    <div class="field">
                        <div class="control">
                            <input class="input" id="hours" name="hours" placeholder="Hours">
                        </div>
                    </div>
                    <label class="label">Engineer Level:</label>
                    <div class="field">
                        <div class="select">
                            <select id="select_engineer_level" name="select_engineer_level">
                                <option value="">Engineer Level</option>
                                <option value="PM">PM</option>
                                <option value="Solutions Technician">Solutions Technician</option>
                                <option value="Solutions Engineer">Solutions Engineer</option>
                                <option value="Senior Solutions Engineer">Senior Solutions Engineer</option>
                                <option value="Solutions Architect">Solutions Architect</option>
                            </select>
                        </div>
                    </div>
                </div>
            {% endfor %}
        </form>
    </div>
    <div id="empty_form" style="display: none;">
        <form action="{% url 'presales' %}" class="presales_formset" data-total-url="{% url 'presales_total' %}" id="emptyPresalesForm" method="post" name="presalesForm">
            {% csrf_token %}

            {{ presales_formset.empty_form }}

            <div class="section">
                <div class="field">
                    <label class="label">Opportunity</label>
                    <div class="select">
                        <select id="empty_select_opportunity" name="select_opportunity">
                            <option value="">Opportunity</option>
                            {% for opportunity in my_opportunities %}
                                <option id="empty_selected_opportunity" name="selected_opportunity" value="{{ opportunity.name }}">{{ opportunity.name }}</option>
                            {% endfor %}
                        </select>
                    </div>
                </div>
                <label class="label">Task Description:</label>
                <div class="field">
                    <div class="control">
                        <input class="input" id="empty_task_description" name="task_description" placeholder="Task Description">
                    </div>
                </div>
                <label class="label">Hours</label>
                <div class="field">
                    <div class="control">
                        <input class="input" id="empty_hours" name="hours" placeholder="Hours">
                    </div>
                </div>
                <label class="label">Engineer Level:</label>
                <div class="field">
                    <div class="select">
                        <select id="empty_select_engineer_level" name="select_engineer_level">
                            <option value="">Engineer Level</option>
                            <option value="PM">PM</option>
                            <option value="Solutions Technician">Solutions Technician</option>
                            <option value="Solutions Engineer">Solutions Engineer</option>
                            <option value="Senior Solutions Engineer">Senior Solutions Engineer</option>
                            <option value="Solutions Architect">Solutions Architect</option>
                        </select>
                    </div>
                </div>
            </div>
        </form>
    </div>

    <div class="field is-inline-flex">
        <div class="control">
            <button class="button is-success" id="add_more" type="button">+</button>
        </div>
    </div>

script.js

<script>
    $('#add_more').click(function () {
        var form_idx = $('#presalesForm-TOTAL_FORMS').val();
        $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
        $('#presalesForm-TOTAL_FORMS').val(parseInt(form_idx) + 1);
    });
</script>

forms.py

# special field names
TOTAL_FORM_COUNT = 'TOTAL_FORMS'
INITIAL_FORM_COUNT = 'INITIAL_FORMS'
MIN_NUM_FORM_COUNT = 'MIN_NUM_FORMS'
MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS'
ORDERING_FIELD_NAME = 'ORDER'
DELETION_FIELD_NAME = 'DELETE'

# default minimum number of forms in a formset
DEFAULT_MIN_NUM = 0

# default maximum number of forms in a formset, to prevent memory exhaustion
DEFAULT_MAX_NUM = 1000


class PresalesForm(forms.Form):
    class Meta:
        model = Presales
        fields = ('selected_opportunity', 'task_description', 'hours', 'selected_engineer_level', 'total_price')

Seeing as this appears to be html code that is injected into an existing page, and the JavaScript does not appear to be injected together with it, I would suspect that the issue is with the JavaScript code not finding that button.

Try the following code:

<script>
    $(document).ready(function () {
        $('body').on('click', '#add_more', function () {
            var form_idx = $('#presalesForm-TOTAL_FORMS').val();
            $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
            $('#presalesForm-TOTAL_FORMS').val(parseInt(form_idx) + 1);
        });
    });
</script>

What happens here is that I am attaching a click listener to the body tags (seeing as I assume it is the parent of the container div), and add a selector that will be the one that this event is triggered for.

.on can be used on dynamically added elements that did not exist when the script was loaded, as opposed to .click .

For further reading regarding .on function .
Differences between .on('click') and .click() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM