Динамическое добавление формы в набор форм Django с помощью Ajax - PullRequest
251 голосов
/ 02 февраля 2009

Я хочу автоматически добавлять новые формы в набор форм Django с помощью Ajax, чтобы, когда пользователь нажимает кнопку «добавить», он запускал JavaScript, который добавляет новую форму (которая является частью набора форм) на страницу.

Ответы [ 15 ]

2 голосов
/ 08 июня 2010

Есть небольшая проблема с функцией 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);
}
1 голос
/ 03 апреля 2017

Поскольку все приведенные выше ответы используют jQuery и делают некоторые вещи немного сложнее, я написал следующий скрипт:

function $(selector, element) {
    if (!element) {
        element = document
    }
    return element.querySelector(selector)
}

function $$(selector, element) {
    if (!element) {
        element = document
    }
    return element.querySelectorAll(selector)
}

function hasReachedMaxNum(type, form) {
    var total = parseInt(form.elements[type + "-TOTAL_FORMS"].value);
    var max = parseInt(form.elements[type + "-MAX_NUM_FORMS"].value);
    return total >= max
}

function cloneMore(element, type, form) {
    var totalElement = form.elements[type + "-TOTAL_FORMS"];
    total = parseInt(totalElement.value);
    newElement = element.cloneNode(true);
    for (var input of $$("input", newElement)) {
        input.name = input.name.replace("-" + (total - 1) + "-", "-" + total + "-");
        input.value = null
    }
    total++;
    element.parentNode.insertBefore(newElement, element.nextSibling);
    totalElement.value = total;
    return newElement
}
var addChoiceButton = $("#add-choice");
addChoiceButton.onclick = function() {
    var choices = $("#choices");
    var createForm = $("#create");
    cloneMore(choices.lastElementChild, "choice_set", createForm);
    if (hasReachedMaxNum("choice_set", createForm)) {
        this.disabled = true
    }
};

Сначала вы должны установить для auto_id значение false и отключить дублирование идентификатора и имени. Поскольку входные имена должны быть уникальными в их форме, вся идентификация выполняется с ними, а не с идентификаторами. Вы также должны заменить form, type и контейнер формы. (В приведенном выше примере choices)

1 голос
/ 09 августа 2012

Да, я бы также рекомендовал просто выводить их в html, если у вас есть конечное число записей. (Если нет, вам придется использовать другой метод).

Вы можете скрыть их так:

{% for form in spokenLanguageFormset %}
    <fieldset class="languages-{{forloop.counter0 }} {% if spokenLanguageFormset.initial_forms|length < forloop.counter and forloop.counter != 1 %}hidden-form{% endif %}">

Тогда JS действительно прост:

addItem: function(e){
    e.preventDefault();
    var maxForms = parseInt($(this).closest("fieldset").find("[name*='MAX_NUM_FORMS']").val(), 10);
    var initialForms = parseInt($(this).closest("fieldset").find("[name*='INITIAL_FORMS']").val(), 10);
    // check if we can add
    if (initialForms < maxForms) {
        $(this).closest("fieldset").find("fieldset:hidden").first().show();
        if ($(this).closest("fieldset").find("fieldset:visible").length == maxForms ){
            // here I'm just hiding my 'add' link
            $(this).closest(".control-group").hide();
        };
    };
}
1 голос
/ 16 сентября 2009

@ Паоло Бергантино

для клонирования всех подключенных обработчиков просто измените строку

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

для

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

для предотвращения этой проблемы.

0 голосов
/ 03 марта 2018

Для программистов, которые охотятся за ресурсами, чтобы немного лучше понять вышеуказанные решения:

Django Dynamic Formsets

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

Документация по Django Formset

В качестве краткого изложения того, что меня смутило: Форма управления содержит обзор форм внутри. Вы должны сохранять эту информацию точной, чтобы Django знал о формах, которые вы добавляете. (Сообщество, пожалуйста, дайте мне предложения, если некоторые из моих формулировок здесь не так. Я новичок в Django.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...