Dynamiczne dodawanie formularza do zestawu form Django za pomocą Ajax
Chcę automatycznie dodawać nowe formularze do zestawu formularzy Django za pomocą Ajax, tak aby gdy użytkownik kliknie przycisk "Dodaj" uruchamiał JavaScript, który dodaje nowy formularz (który jest częścią zestawu formularzy) do strony.
15 answers
Tak to robię, używając jQuery :
Mój szablon:
<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>
W pliku 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);
}
Co robi:
cloneMore
przyjmuje selector
jako pierwszy argument, a type
formset jako drugi. {[3] } powinien przekazać to, co powinien powielać. W tym przypadku przekazuję div.table:last
, aby jQuery szukał ostatniej tabeli z klasą table
. Część :last
jest ważna, ponieważ selector
jest również używana do określenia, co nowy formularz zostanie wstawiony po. Bardziej niż prawdopodobne, że chcesz go na końcu reszty formularzy. Argument type
jest tak, że możemy zaktualizować pole management_form
, w szczególności TOTAL_FORMS
, jak również rzeczywiste pola formularza. Jeśli masz zestaw formularzy pełen, powiedzmy, modeli Client
, pola zarządzania będą miały identyfikatory id_clients-TOTAL_FORMS
i id_clients-INITIAL_FORMS
, podczas gdy pola formularza będą miały format id_clients-N-fieldname
z N
jako numerem formularza, zaczynającym się od 0
. Więc z argumentem type
Funkcja cloneMore
patrzy na ile formularze są obecnie i przechodzą przez każde wejście i etykietę wewnątrz nowego formularza, zastępując wszystkie nazwy pól / identyfikatory z czegoś w rodzaju id_clients-(N)-name
na id_clients-(N+1)-name
i tak dalej. Po zakończeniu aktualizuje pole TOTAL_FORMS
, aby odzwierciedlić nowy formularz i dodaje go na końcu zestawu.
Ta funkcja jest dla mnie szczególnie pomocna, ponieważ sposób jej konfiguracji pozwala mi używać jej w całej aplikacji, gdy chcę dostarczyć więcej formularzy w zestawie formularzy i nie sprawia, że muszę mieć ukryty formularz "szablon" do powielenia, o ile podam mu nazwę zestawu formularzy i format, w którym formularze są ułożone. Mam nadzieję, że to pomoże.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-16 06:42:13
Uproszczona wersja odpowiedzi Paolo za pomocą empty_form
jako szablon.
<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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-28 09:42:33
Wysłałem Fragment z aplikacji, nad którą pracowałem jakiś czas temu. Podobny do Paolo, ale pozwala również na kasowanie formularzy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-22 12:17:17
Sugestia Paolo działa pięknie z jednym zastrzeżeniem - przyciskami wstecz/do przodu przeglądarki.
Dynamiczne elementy utworzone za pomocą skryptu Paolo nie będą renderowane, jeśli użytkownik powróci do formsetu za pomocą przycisku back/forward. Problem, który może być łamanie umowy dla niektórych.
Przykład:
1) użytkownik dodaje dwa nowe formularze do zestawu formularzy za pomocą przycisku "Dodaj-więcej"
2) użytkownik wypełnia formularze i przesyła zestaw formularzy
3) Użytkownik kliknie przycisk Wstecz w przeglądarce
4) Formset jest teraz zredukowany do oryginalnego formularza, wszystkich dynamicznie dodawanych formularzy nie ma
To nie jest wada skryptu Paolo w ogóle; ale fakt życia z manipulacją dom i cache przeglądarki.
Przypuszczam, że można zapisać wartości formularza w sesji i mieć trochę magii ajax, gdy zestaw formularzy ładuje się ponownie, aby utworzyć elementy i przeładować wartości z sesji; ale w zależności od tego, jak chcesz być o tym samym użytkowniku i wiele wystąpień formularza może stać się bardzo skomplikowane.
Czy ktoś ma dobry pomysł na poradzenie sobie z tym?
Dzięki!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-21 12:52:17
Sprawdź następujące rozwiązania dynamicznych form django:
Http://code.google.com/p/django-dynamic-formset/
Https://github.com/javisantana/django-dinamyc-form/tree/master/frm
Oba używają jQuery i są specyficzne dla django. Pierwszy wydaje się nieco bardziej dopracowany i oferuje pobieranie, które pochodzi z/dema, które są doskonałe.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-26 20:41:55
Symulować i naśladować:
- Utwórz zestaw formularzy odpowiadający sytuacji przed kliknięciem przycisku "Dodaj".
- załaduj stronę, zobacz źródło i zanotuj wszystkie pola
<input>
. - zmodyfikuj zestaw formularzy tak, aby odpowiadał sytuacji po kliknięciu przycisku "Dodaj" (Zmień liczbę dodatkowych pól).
- załaduj stronę, zobacz źródło i zanotuj, jak zmieniły się pola
<input>
. - Tworzenie JavaScript, który modyfikuje DOM w odpowiedni sposób przenosi go ze stanu przed do stanu po .
- Dołącz ten JavaScript do przycisku "Dodaj".
Chociaż wiem, że formularze używają specjalnych ukrytych pól <input>
i wiem w przybliżeniu, co skrypt musi zrobić, nie przypominam sobie szczegółów z głowy. To, co opisałem powyżej, to to, co bym zrobił w twojej sytuacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-09 20:49:11
Istnieje jQuery plugin do tego , użyłem go z zestawem inline_form w Django 1.3 i działa idealnie, włączając w to prepopulację, dodawanie, usuwanie formularzy po stronie klienta i wiele zestawów inline_formsets.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-04 19:57:20
Jedną z opcji byłoby utworzenie zestawu formularzy z każdym możliwym formularzem, ale początkowo Ustaw nieodwzajemnione formularze na hidden-ie, display: none;
. Gdy jest to konieczne, aby wyświetlić formularz, Ustaw wyświetlacz css na block
lub cokolwiek jest właściwe.
Bez wiedzy więcej szczegółów na temat tego, co robi twój "Ajax", trudno jest dać bardziej szczegółową odpowiedź.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-02 00:49:35
Kolejna wersja cloneMore, która pozwala na selektywną sanityzację pól. Użyj go, gdy musisz zapobiec usunięciu kilku pól.
$('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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-04 14:00:25
Jest mały problem z funkcją cloneMore. Ponieważ czyści również wartość automatycznie wygenerowanych ukrytych pól django, powoduje, że django będzie narzekać, jeśli spróbujesz zapisać zestaw formularzy z więcej niż jednym pustym formularzem.
Oto poprawka:
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);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-07 21:22:30
Myślę, że to o wiele lepsze rozwiązanie.
Jak zrobić dynamiczny formset w Django?
Robi rzeczy nie:
- Dodaj formularz, gdy nie ma form początkowych
- lepiej obsługuje javascript w formie, na przykład django-ckeditor
- Zachowaj początkowe dane
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:28
@ Paolo Bergantino
Aby sklonować wszystkie dołączone manipulatory wystarczy zmodyfikować linię
var newElement = $(selector).clone();
Dla
var newElement = $(selector).clone(true);
Aby zapobiec temu problemowi.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44
Tak też polecam po prostu renderowanie ich w html, jeśli masz skończoną liczbę wpisów. (Jeśli nie będziesz musiał użyć innej metody).
Możesz je ukryć w ten sposób:
{% for form in spokenLanguageFormset %}
<fieldset class="languages-{{forloop.counter0 }} {% if spokenLanguageFormset.initial_forms|length < forloop.counter and forloop.counter != 1 %}hidden-form{% endif %}">
Wtedy js jest naprawdę proste:
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();
};
};
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-09 01:05:17
Ponieważ wszystkie powyższe odpowiedzi używają jQuery i sprawiają, że niektóre rzeczy są nieco skomplikowane napisałem następujący skrypt:
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
}
};
Najpierw należy ustawić auto_id na false i wyłączyć powielanie id i name. Ponieważ nazwy wejściowe muszą być unikalne w tej formie, Cała identyfikacja odbywa się za ich pomocą, a nie za pomocą identyfikatorów.
Musisz również wymienić form
, type
oraz kontener zestawu formularzy. (W powyższym przykładzie choices
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-03 16:40:57
Dla programistów, którzy polują na zasoby, aby lepiej zrozumieć powyższe rozwiązania:
Po przeczytaniu powyższego linku dokumentacja Django i poprzednie rozwiązania powinny mieć o wiele więcej sensu.
Jako krótkie podsumowanie tego, co byłem zdezorientowany: formularz zarządzania zawiera przegląd formularzy wewnątrz. Musisz zachować te informacje w celu aby Django był świadomy form, które dodajesz. (Społeczność, proszę dać mi sugestie, jeśli niektóre z moich sformułowań jest wyłączony tutaj. Jestem nowy w Django.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-03 14:53:19