Skip to content

Commit 7b49f08

Browse files
Required file field behaviour in stream field forms (#4457)
Fixes #4401
1 parent 50f08b1 commit 7b49f08

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

hypha/apply/stream_forms/fields.py

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.conf import settings
2+
from django.core.exceptions import ValidationError
23
from django.core.validators import FileExtensionValidator
34
from django.forms import FileField
45
from django_file_form.fields import MultipleUploadedFileField, UploadedFileField
@@ -13,6 +14,8 @@ class MultiFileField(MultipleUploadedFileField):
1314
widget = MultiFileFieldWidget
1415

1516
def clean(self, value, initial):
17+
if self.required and not value:
18+
raise ValidationError(self.error_messages["required"], code="required")
1619
if not value:
1720
return []
1821
old_files = [
@@ -56,6 +59,8 @@ class SingleFileField(UploadedFileField):
5659
widget = SingleFileFieldWidget
5760

5861
def clean(self, value, initial):
62+
if self.required and not value and not initial:
63+
raise ValidationError(self.error_messages["required"], code="required")
5964
if not value:
6065
return
6166
if hasattr(value, "is_placeholder") and value.is_placeholder and initial:

hypha/static_src/javascript/file-uploads.js

+35
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,39 @@ htmx.onLoad(function () {
2727
});
2828
}
2929
}
30+
31+
// Handle client side validation for required file fields
32+
let fileInputs = document.querySelectorAll("input[type='file'][required]");
33+
34+
fileInputs.forEach((input) => {
35+
input.addEventListener("invalid", function (event) {
36+
event.preventDefault(); // Prevent default browser behavior
37+
38+
let errorMessage = "This field is required.";
39+
// Find the closest dff-uploader wrapper and display an error
40+
let container = input.closest(".form__item");
41+
42+
let errorDiv = container.querySelector(".form__error-text");
43+
44+
errorDiv = document.createElement("p");
45+
errorDiv.classList.add("form__error-text");
46+
container.appendChild(errorDiv);
47+
errorDiv.innerText = errorMessage; // Show error message
48+
});
49+
50+
input.addEventListener("change", function () {
51+
let container = input.closest(".form__item");
52+
let errorDiv = container.querySelector(".form__error-text");
53+
54+
if (errorDiv) {
55+
if (
56+
input.files.length > 0 ||
57+
container.querySelector(".dff-file") !== null
58+
) {
59+
errorDiv.classList.remove("form__error-text");
60+
errorDiv.innerText = ""; // Clear the error only when a file is selected
61+
}
62+
}
63+
});
64+
});
3065
});

0 commit comments

Comments
 (0)