我在使用Django
和django-crispy-forms
构建的表单中有一个bootstrap 4.0.0-alpha.6
表单集。它看起来像这样:
{% block content %}
<div>
<h1 class="text-center">Create New Activity</h1>
<div class="row">
<div class="col"></div>
<div class="col-md-8 col-lg-8">
<form role="form" method="post">
{% csrf_token %}
{{ form|crispy }}
{{ activitykeycharacteristics_formset|crispy }}
<hr>
<button class="primaryAction btn btn-primary pull-right ml-1" type="submit">{% trans "Submit" %}</button>
<a class="btn btn-secondary pull-right" href="{{ request.META.HTTP_REFERER }}" role="button">{% trans "Cancel" %}</a>
</form>
</div>
<div class="col"></div>
</div>
</div>
{% endblock content %}
我一直在尝试做的是添加和删除按钮,以便我可以添加或删除formset中的表单。目前它在formset中使用一个表单进行渲染,因此只能看到一个添加按钮,但是一旦有多个删除按钮也应该被看到。
我非常确定最好的方法是使用jQuery
添加和删除表单,但我还没有能够让它正常工作。我认为我在这个SO question中使用Dave的答案使用了添加按钮。但我无法正确更新输入的索引。我无法在那个问题上得到公认的答案,而且我不确定原因。
formset中的表单由两个django-autocomplete-light下拉列表组成。
如果有人能帮助我,我会非常感激。
感谢您的时间。
- UPDATE -
以下是带有更新模板的js代码:
js file:
function updateElementIndex(el, prefix, ndx) {
let id_regex = new RegExp('(' + prefix + '-\\d+)');
let replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.key_characteristic) el.key_characteristic = el.key_characteristic.replace(id_regex, replacement);
if (el.data_type) el.data_type = el.data_type.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
let newElement = $(selector).clone(true);
let total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
// Not sure how to adapt this to work with two inputs
let id;
let key_characteristic = $(this).attr('key_characteristic');
let data_type = $(this).attr('data_type');
if (key_characteristic) {
key_characteristic.replace('-' + (total-1) + '-', '-' + total + '-');
id = 'id_' + key_characteristic;
} else if (data_type) {
data_type.replace('-' + (total-1) + '-', '-' + total + '-');
id = 'id_' + data_type;
}
$(this).attr({'key_characteristic': key_characteristic, 'data_type': data_type, 'id': id}).val('').removeAttr('checked');
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
function deleteForm(prefix, btn) {
let total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('#formset').remove();
let forms = $('#formset');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (let i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
}
$('#add-form').on('click', function(e) {
e.preventDefault();
cloneMore('#formset:last', 'form');
});
$('#remove-form').on('click', function(e) {
e.preventDefault();
deleteForm('form', $(this));
});
更新的模板:
{% block content %}
<div>
<h1 class="text-center">Create New Activity</h1>
<div class="row">
<div class="col"></div>
<div class="col-md-8 col-lg-8">
<form role="form" method="post">
{% csrf_token %}
{{ form|crispy }}
<div id="formset">
{{ activitykeycharacteristics_formset.management_form }}
{% for form in activitykeycharacteristics_formset.forms %}
{{ form|crispy }}
{% if forloop.counter != 1 %}
<button class="btn btn-primary" id="add-form"><i class="fa fa-plus"></i></button>
<button class="btn btn-danger" id="remove-form"><i class="fa fa-minus"></i></button>
{% else %}
<button class="btn btn-primary" id="add-form"><i class="fa fa-plus"></i></button>
{% endif %}
{% endfor %}
</div>
{# {{ activitykeycharacteristics_formset|crispy }}#}
<hr>
<button class="primaryAction btn btn-primary pull-right ml-1" type="submit">{% trans "Submit" %}</button>
<a class="btn btn-secondary pull-right" href="{{ request.META.HTTP_REFERER }}" role="button">{% trans "Cancel" %}</a>
</form>
</div>
<div class="col"></div>
</div>
</div>
{% endblock content %}