Created
March 21, 2023 16:05
-
-
Save vandorjw/4294a6cd37ea1b861eb31f9e2322d68e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Formset(element) { | |
/* | |
Dynamic Formset handler for Django formsets. | |
Events: | |
* init.formset | |
* add-form.formset | |
* remove-form.formset | |
* renumber-form.formset | |
*/ | |
if (!(this instanceof Formset)) { | |
return new Formset(element); | |
} | |
var formset = this; | |
var emptyForm = element.querySelector('.empty-form').firstElementChild; | |
var formsList = element.querySelector('.forms'); | |
var initialForms = element.querySelector('[name$=INITIAL_FORMS]'); | |
var totalForms = element.querySelector('[name$=TOTAL_FORMS]'); | |
var prefix = initialForms.name.replace(/INITIAL_FORMS$/, ''); | |
function addForm(event) { | |
// Duplicate empty form. | |
var newForm = emptyForm.cloneNode(true); | |
// Update all references to __prefix__ in the elements names. | |
renumberForm(newForm, '__prefix__', totalForms.value); | |
// Make it able to delete itself. | |
newForm.querySelector('[data-formset-remove-form]').addEventListener('click', removeForm); | |
// Append the new form to the formsList. | |
formsList.insertAdjacentElement('beforeend', newForm); | |
element.dispatchEvent(new CustomEvent('add-form.formset', { | |
detail: { | |
form: newForm, | |
formset: formset | |
} | |
})); | |
// Update the totalForms.value | |
totalForms.value = Number(totalForms.value) + 1; | |
} | |
function getForm(target) { | |
var parent = target.parentElement; | |
if (parent == document) { | |
return null; | |
} | |
if (parent == formsList) { | |
return target; | |
} | |
return getForm(parent); | |
} | |
function renumberForm(form, oldValue, newValue) { | |
var matchValue = prefix + oldValue.toString() | |
var match = new RegExp(matchValue); | |
var replace = prefix + newValue.toString(); | |
['name', 'id', 'for'].forEach(function (attr) { | |
form.querySelectorAll('[' + attr + '*=' + matchValue + ']').forEach(function (el) { | |
el.setAttribute(attr, el.getAttribute(attr).replace(match, replace)); | |
}); | |
}); | |
element.dispatchEvent(new CustomEvent('renumber-form.formset', { | |
detail: { | |
form: form, | |
oldValue: oldValue, | |
newValue: newValue, | |
formset: formset | |
} | |
})); | |
} | |
function removeForm(event) { | |
// Find the form "row": the child of formsList that is the parent of the element | |
// that triggered this event. | |
var formToRemove = getForm(event.target); | |
// Renumber the rows that come after us. | |
var nextElement = formToRemove.nextElementSibling; | |
var nextElementIndex = Array.prototype.indexOf.call(formsList.children, formToRemove); | |
while (nextElement) { | |
renumberForm(nextElement, nextElementIndex + 1, nextElementIndex); | |
nextElement = nextElement.nextElementSibling; | |
nextElementIndex = nextElementIndex + 1; | |
} | |
// Remove this row. | |
formToRemove.remove(); | |
element.dispatchEvent(new CustomEvent('remove-form.formset', { | |
detail: { | |
form: formToRemove, | |
formset: formset | |
} | |
})); | |
// Decrement the management form's count. | |
totalForms.value = Number(totalForms.value) - 1; | |
} | |
element.querySelector('[data-formset-add-form]').addEventListener('click', addForm); | |
// Allow existing forms to remove themselves. | |
formsList.querySelectorAll('[data-formset-remove-form]').forEach( | |
rmBtn => {rmBtn.addEventListener('click', removeForm); | |
}); | |
element.formset = this; | |
element.dispatchEvent(new CustomEvent('init.formset', { | |
detail: { | |
formset: this | |
} | |
})); | |
this.addForm = addForm; | |
} |
Corresponding HTML
<script src="~/js/formset_manager.js"></script>
<h1>File Upload</h1>
<p>Instructions go here</p>
<form id="documentUploadForm" enctype="multipart/form-data" method="post">
<input type="hidden" name="TOTAL_FORMS" value="1" />
<input type="hidden" name="PREFIX" value="FileUploadFormSet" />
<fieldset disabled class="empty-form" style="display:none">
<fieldset>
<div class="form-group row">
<div class="col-sm-10">
<label asp-for="EmptyForm.FileUploadField"></label>
<input asp-for="EmptyForm.FileUploadField" type="file" accept=".pdf">
<span asp-validation-for="EmptyForm.FileUploadField" class="field-validation-error"></span>
</div>
<div class="col-sm-2">
<button class="btn-danger btn btn-sm" data-formset-remove-form>Remove</button>
</div>
</div>
</fieldset>
</fieldset>
<div class="forms">
@{
int i = 0;
@foreach (var form in Model.FileUploadFormSet)
{
<fieldset>
<div class="form-group row">
<div class="col-sm-10">
<label asp-for="FileUploadFormSet[i].FileUploadField"></label>
<input asp-for="FileUploadFormSet[i].FileUploadField" type="file" accept=".pdf">
<span asp-validation-for="FileUploadFormSet[i].FileUploadField" class="field-validation-error"></span>
</div>
</div>
</fieldset>
i++;
}
}
</div>
<fieldset class="controls">
<button class="btn btn-primary btn-sm" type="button" data-formset-add-form>Add Another File</button>
</fieldset>
<hr />
<input asp-page-handler="Upload" class="btn btn-success" type="submit" value="Upload" />
</form>
<script type="text/javascript">
new Formset(document.querySelector('#documentUploadForm'));
</script>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
modified for .NET