Динамично добавляя форму к Django formset с Ajax

ссылки на элементы, возвращаемые функциями .find_element_*, взяты из начальной загрузки страницы. Когда вы click(), вы уходите от начальной страницы, делая все ссылки на элементы устаревшими. Вам нужно будет снова вызвать find_elements, прежде чем отправлять ключи новым элементам.

253
задан Dmitriy 18 July 2014 в 00:37
поделиться

7 ответов

Это - то, как я делаю это, с помощью [1 124] jQuery:

Мой шаблон:

<h3>My Services</h3>
{{ serviceFormset.management_form }}
{% for form in serviceFormset.forms %}
    <div class='table'>
    <table class='no_error'>
        {{ form.as_table }}
    </table>
    </div>
{% endfor %}
<input type="button" value="Add More" id="add_more">
<script>
    $('#add_more').click(function() {
        cloneMore('div.table:last', 'service');
    });
</script>

В файле JavaScript:

function cloneMore(selector, type) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + type + '-TOTAL_FORMS').val();
    newElement.find(':input').each(function() {
        var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
        var id = 'id_' + name;
        $(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
    });
    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);
}

, Что это делает:

cloneMore принимает selector как первый аргумент, и type из formset как 2-й. То, что эти selector должно сделать, передать его, что это должно копировать. В этом случае я передаю его div.table:last так, чтобы jQuery искал последнюю таблицу с классом table. :last часть его важна, потому что эти selector также используется для определения то, что новая форма будет вставлена после. Более, чем вероятный Вы хотели бы это в конце остальной части форм. type аргумент - то, так, чтобы мы могли обновить management_form поле, особенно TOTAL_FORMS, а также фактические поля формы. Если у Вас будет formset полный из, скажем, Client модели, то поля управления будут иметь идентификаторы id_clients-TOTAL_FORMS и id_clients-INITIAL_FORMS, в то время как поля формы будут в формате [1 116] с [1 117] являющийся числом формы, начиная с [1 118]. Таким образом с type аргумент cloneMore функция смотрит на то, сколько там в настоящее время формы, и проходит каждый вход и маркировку в новой форме, заменяющей все поле, names/ids от чего-то как [1 121] к [1 122] и так далее. После того, как это будет закончено, это обновляет TOTAL_FORMS поле для отражения новой формы и добавляет его до конца набора.

Эта функция особенно полезна мне, потому что способ, которым это - установка, это позволяет мне использовать его всюду по приложению, когда я хочу обеспечить больше форм в formset, и не делает меня, должен иметь скрытую "шаблонную" форму для дублирования, пока я передаю его имя formset и формат, в котором размечаются формы. Надежда это помогает.

213
ответ дан Paolo Bergantino 23 November 2019 в 02:51
поделиться

Моделируйте и подражайте:

  • Создают formset, который соответствует ситуации прежде нажатие "добавить" кнопка.
  • Загрузка страница, просмотрите источник и обратите внимание на весь <input> поля.
  • Изменяют formset для соответствия ситуации после нажатие "добавить" кнопка (измените количество дополнительных полей).
  • Загрузка страница, просмотрите источник и обратите внимание на как эти <input> измененные поля.
  • Создают некоторый JavaScript, который изменяет DOM подходящим способом переместить его от прежде состояние к после состояние.
  • Присоединение, что JavaScript к "добавить" кнопке.

, В то время как я действительно знаю, formsets используют особенный скрытый <input> поля и знают приблизительно, что должен сделать сценарий, я не вспоминаю детали первое, что пришло на ум. То, что я описал выше, - то, что я сделал бы в Вашей ситуации.

11
ответ дан akaihola 23 November 2019 в 02:51
поделиться

Я имею , отправил отрывок из приложения, я продолжил работать некоторое время назад. Подобный Паоло, но также и позволяет Вам, удаляют формы.

25
ответ дан elo80ka 23 November 2019 в 02:51
поделиться

Одна опция состояла бы в том, чтобы создать formset с каждой возможной формой, но первоначально установить необязательные формы на скрытый - т.е., display: none;. Когда необходимо отобразить форму, установить, это - дисплей CSS к block или независимо от того, что является соответствующим.

Без знают больше деталей того, что делает Ваш "Ajax", трудно дать более подробный ответ.

4
ответ дан Daniel Naab 23 November 2019 в 02:51
поделиться

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!

18
ответ дан 23 November 2019 в 02:51
поделиться

@Paolo Bergantino

to clone all the handlers attached just modify the line

var newElement = $(selector).clone();

for

var newElement = $(selector).clone(true);

to prevent this problem.

1
ответ дан 23 November 2019 в 02:51
поделиться

Есть небольшая проблема с функцией cloneMore. Поскольку он также очищает значение автоматически сгенерированных скрытых полей django, он заставляет django жаловаться, если вы пытаетесь сохранить набор форм с более чем одной пустой формой.

Вот исправление:

function cloneMore(selector, type) {
    var newElement = $(selector).clone(true);
    var total = $('#id_' + type + '-TOTAL_FORMS').val();
    newElement.find(':input').each(function() {
        var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
        var id = 'id_' + name;

        if ($(this).attr('type') != 'hidden') {
            $(this).val('');
        }
        $(this).attr({'name': name, 'id': id}).removeAttr('checked');
    });
    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);
}
2
ответ дан 23 November 2019 в 02:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: