How to have multiple dynamic forms on the same page?
I have multiple of the same inline formsets on the same page. On other pages I already have a single formset with dynamic "add" and "remove" buttons. However the javascript starts acting strange and I am unable to reuse variables among the different inline formsets.
In order to have a single dynamic from I am using:
<script>
document.addEventListener('click', (event) => {
if (event.target.id === "add") {
add_form(event)
}
if (event.target.id === "remove") {
remove_form(event)
}
})
function add_form(event) {
if (event) {
event.preventDefault()
}
const totalNewForms = document.getElementById('id_form-TOTAL_FORMS')
const currentForms = document.getElementsByClassName('form')
const currentFormCount = currentForms.length // + 1
const formCopyTarget = document.getElementById('formset')
const copyEmptyFormEl = document.getElementById('empty-form').cloneNode(true)
copyEmptyFormEl.setAttribute('class', 'form')
copyEmptyFormEl.setAttribute('id', `form-${currentFormCount}`)
const regex = new RegExp('__prefix__', 'g')
copyEmptyFormEl.innerHTML = copyEmptyFormEl.innerHTML.replace(regex, currentFormCount)
totalNewForms.setAttribute('value', currentFormCount + 1)
// now add new empty form element to our html form
formCopyTarget.append(copyEmptyFormEl)
}
function remove_form(event) {
if (event) {
event.preventDefault()
}
const totalNewForms = document.getElementById('id_form-TOTAL_FORMS')
const currentForms = document.getElementsByClassName('form')
const currentFormCount = currentForms.length
//const regex = new RegExp(`id_form-${currentFormCount-1}`)
const deleteFormTarget = document.getElementById(`form-${currentFormCount - 1}`)
totalNewForms.setAttribute('value', currentFormCount - 1)
deleteFormTarget.outerHTML = "";
}
</script>
I have attempted to create django context variables that are unique to each inline formset (all same parent model, different child model). I am able to set the variables but when I try to use the variables the django template does not render the javascript value of the variable, it only renders the name of the context variable I set in the views.
Example
View:
def get_context_data(self, **kwargs):
context = super(HXUpdateView, self).get_context_data(**kwargs)
context['formset'] = InlineFormsetFactory(
form_kwargs={'user': self.request.user}, instance=self.object, prefix=f"{self.object.pk}-form")
context['addButton'] = f"add-{self.object.pk}"
context['total_forms_id'] = f"id_{self.object.pk}-form-TOTAL_FORMS"
context['totalNewForms'] = f"totalNewForms{self.object.pk}"
context['FormClass'] = f"{self.object}class"
context['currentForms'] = f"currentForms{self.object.pk}"
context['currentFormCount'] = f"currentFormCount{self.object.pk}"
context['formCopyTarget'] = f"formCopyTarget{self.object.pk}"
context['eFormsetId'] = f"UpdateFormset{self.object.pk}"
context['copyEmptyFormEl'] = f"copyEmptyFormEl{self.object.pk}"
context['emptyForm'] = f"emptyForm{self.object.pk}"
context['regex'] = f"regex{self.object.pk}"
context['removeButton'] = f"removeButton{self.object.pk}"
context['deleteFormTargetId'] = f"deleteFormTargetId{self.object.pk}"
context['deleteFormTarget'] = f"deleteFormTarget{self.object.pk}"
context['one'] = 1
return context
template javascript:
<script>
document.addEventListener('click', (event) => {
if (event.target.id === "{{ addButton }}") {
add_form(event)
}
if (event.target.id === "{{ removeButton }}") {
remove_form(event)
}
})
function add_form(event) {
if (event) {
event.preventDefault()
}
const {{ totalNewForms }} = document.getElementById("{{ total_forms_id }}");
const {{ currentForms }} = document.getElementsByClassName('{{ FormClass }}');
const {{ currentFormCount }} = {{ currentForms }}.length;
const {{ formCopyTarget }} = document.getElementById('{{ FormsetId }}');
const {{ copyEmptyFormEl }} = document.getElementById('{{ emptyForm }}').cloneNode(true);
{{ copyEmptyFormEl }}.setAttribute('class', '{{ FormClass }}');
{{ copyEmptyFormEl }}.setAttribute('id', `form-{{ currentFormCount }}`);
const {{ regex }} = new RegExp('__prefix__', 'g');
{{ copyEmptyFormEl }}.innerHTML = {{ copyEmptyFormEl }}.innerHTML.replace({{ regex }}, {{ currentFormCount }});
{{ totalNewForms }}.setAttribute('value', {{ currentFormCount }} + 1);
{{ formCopyTarget }}.append({{ copyEmptyFormEl }});
console.log({{ copyEmptyFormEl }});
}
function removeform(event) {
if (event) {
event.preventDefault()
}
const {{ totalNewForms }} = document.getElementById('{{ total_forms_id }}');
const {{ currentForms }} = document.getElementsByClassName('{{ FormClass }}');
const {{ currentFormCount }} = {{ currentForms }}.length;
//const regex = new RegExp(`id_form-${currentFormCount-1}`);
const {{ deleteFormTarget }} = document.getElementById(`form-${currentFormCount - 1}`)
console.log({{ deleteFormTarget }})
}
</script>