Dynamically adding a form to a Django formset with Ajax

后端 未结 15 1923
不思量自难忘°
不思量自难忘° 2020-11-22 03:09

I want to automatically add new forms to a Django formset using Ajax, so that when the user clicks an \"add\" button it runs JavaScript that adds a new form (which is part o

相关标签:
15条回答
  • 2020-11-22 03:31

    Paolo's suggestion works beautifully with one caveat - the browser's back/forward buttons.

    The dynamic elements created with Paolo's script will not be rendered if the user returns to the formset using the back/forward button. An issue that may be a deal breaker for some.

    Example:

    1) User adds two new forms to the formset using the "add-more" button

    2) User populates the forms and submits the formset

    3) User clicks the back button in the browser

    4) Formset is now reduced to the original form, all dynamically added forms are not there

    This is not a defect with Paolo's script at all; but a fact of life with dom manipulation and browser's cache.

    I suppose one could store the values of the form in the session and have some ajax magic when the formset loads to create the elements again and reload the values from the session; but depending on how anal you want to be about the same user and multiple instances of the form this may become very complicated.

    Anyone has a good suggestion for dealing with this?

    Thanks!

    0 讨论(0)
  • 2020-11-22 03:33

    Another cloneMore version, which allows for selective sanitization of fields. Use it when you need to prevent several fields from being erased.

    $('table tr.add-row a').click(function() {
        toSanitize = new Array('id', 'product', 'price', 'type', 'valid_from', 'valid_until');
        cloneMore('div.formtable table tr.form-row:last', 'form', toSanitize);
    });
    
    function cloneMore(selector, type, sanitize) {
        var newElement = $(selector).clone(true);
        var total = $('#id_' + type + '-TOTAL_FORMS').val();
        newElement.find(':input').each(function() {
            var namePure = $(this).attr('name').replace(type + '-' + (total-1) + '-', '');
            var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
            var id = 'id_' + name;
            $(this).attr({'name': name, 'id': id}).removeAttr('checked');
    
            if ($.inArray(namePure, sanitize) != -1) {
                $(this).val('');
            }
    
        });
        newElement.find('label').each(function() {
            var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
            $(this).attr('for', newFor);
        });
        total++;
        $('#id_' + type + '-TOTAL_FORMS').val(total);
        $(selector).after(newElement);
    }
    
    0 讨论(0)
  • 2020-11-22 03:34

    Check out the following solutions to dynamic django forms:

    http://code.google.com/p/django-dynamic-formset/

    https://github.com/javisantana/django-dinamyc-form/tree/master/frm

    They both make use of jQuery and are django-specific. The first seems a bit more polished and offers a download that comes w/demos which are excellent.

    0 讨论(0)
  • 2020-11-22 03:34

    One option would be to create a formset with every possible form, but initially set the unrequired forms to hidden - ie, display: none;. When it's necessary to display a form, set it's css display to block or whatever is appropriate.

    Without know more details of what your "Ajax" is doing, it's hard to give a more detailed response.

    0 讨论(0)
  • 2020-11-22 03:37

    Simplified version of Paolo's answer using empty_form as a template.

    <h3>My Services</h3>
    {{ serviceFormset.management_form }}
    <div id="form_set">
        {% for form in serviceFormset.forms %}
            <table class='no_error'>
                {{ form.as_table }}
            </table>
        {% endfor %}
    </div>
    <input type="button" value="Add More" id="add_more">
    <div id="empty_form" style="display:none">
        <table class='no_error'>
            {{ serviceFormset.empty_form.as_table }}
        </table>
    </div>
    <script>
        $('#add_more').click(function() {
            var form_idx = $('#id_form-TOTAL_FORMS').val();
            $('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
            $('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
        });
    </script>
    
    0 讨论(0)
  • 2020-11-22 03:37

    Simulate and imitate:

    • Create a formset which corresponds to the situation before clicking the "add" button.
    • Load the page, view the source and take a note of all <input> fields.
    • Modify the formset to correspond to the situation after clicking the "add" button (change the number of extra fields).
    • Load the page, view the source and take a note of how the <input> fields changed.
    • Create some JavaScript which modifies the DOM in a suitable way to move it from the before state to the after state.
    • Attach that JavaScript to the "add" button.

    While I do know formsets use special hidden <input> fields and know approximately what the script must do, I don't recall the details off the top of my head. What I described above is what I would do in your situation.

    0 讨论(0)
提交回复
热议问题