requesting entity working - code still wip

This commit is contained in:
David Kennedy 2025-01-16 14:13:51 -05:00
parent 74ef30b52d
commit 6a49f9e373
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
4 changed files with 163 additions and 70 deletions

View file

@ -1038,7 +1038,7 @@ const noop = () => {};
* @param {string} value The new value of the element
*/
const changeElementValue = function (el) {
let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
const elementToChange = el;
elementToChange.value = value;
const event = new CustomEvent("change", {
@ -1168,22 +1168,14 @@ const enhanceComboBox = _comboBoxEl => {
placeholder
});
}
// DOTGOV - allowing for defaultValue to be empty
//if (defaultValue) {
// for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
// const optionEl = selectEl.options[i];
// if (optionEl.value === defaultValue) {
// selectedOption = optionEl;
// break;
// }
// }
//}
for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
const optionEl = selectEl.options[i];
if ((optionEl.value === defaultValue) || (!optionEl.value && !defaultValue)) {
selectedOption = optionEl;
break;
}
if (defaultValue) {
for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
const optionEl = selectEl.options[i];
if (optionEl.value === defaultValue) {
selectedOption = optionEl;
break;
}
}
}
/**
@ -1234,11 +1226,9 @@ const enhanceComboBox = _comboBoxEl => {
input.setAttribute(key, value);
}));
comboBoxEl.insertAdjacentElement("beforeend", input);
// DOTGOV - modified the aria-label of the clear input button to Reset selection to reflect changed button behavior
// <button type="button" class="${CLEAR_INPUT_BUTTON_CLASS}" aria-label="Clear the select contents">&nbsp;</button>
comboBoxEl.insertAdjacentHTML("beforeend", Sanitizer.escapeHTML`
<span class="${CLEAR_INPUT_BUTTON_WRAPPER_CLASS}" tabindex="-1">
<button type="button" class="${CLEAR_INPUT_BUTTON_CLASS}" aria-label="Reset selection">&nbsp;</button>
<button type="button" class="${CLEAR_INPUT_BUTTON_CLASS}" aria-label="Clear the select contents">&nbsp;</button>
</span>
<span class="${INPUT_BUTTON_SEPARATOR_CLASS}">&nbsp;</span>
<span class="${TOGGLE_LIST_BUTTON_WRAPPER_CLASS}" tabindex="-1">
@ -1374,12 +1364,8 @@ const displayList = el => {
for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
const optionEl = selectEl.options[i];
const optionId = `${listOptionBaseId}${options.length}`;
// DOTGOV: modified combobox to allow for options with blank value
//if (optionEl.value && (disableFiltering || isPristine || !inputValue || regex.test(optionEl.text))) {
if ((disableFiltering || isPristine || !inputValue || regex.test(optionEl.text))) {
// DOTGOV: modified combobox to allow blank option value selections to be considered selected
//if (selectEl.value && optionEl.value === selectEl.value) {
if (selectEl.value && optionEl.value === selectEl.value || (!selectEl.value && !optionEl.value)) {
if (optionEl.value && (disableFiltering || isPristine || !inputValue || regex.test(optionEl.text))) {
if (selectEl.value && optionEl.value === selectEl.value) {
selectedItemId = optionId;
}
if (disableFiltering && !firstFoundId && regex.test(optionEl.text)) {
@ -1514,28 +1500,17 @@ const resetSelection = el => {
} = getComboBoxContext(el);
const selectValue = selectEl.value;
const inputValue = (inputEl.value || "").toLowerCase();
// DOTGOV - allow for option value to be empty string
//if (selectValue) {
// for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
// const optionEl = selectEl.options[i];
// if (optionEl.value === selectValue) {
// if (inputValue !== optionEl.text) {
// changeElementValue(inputEl, optionEl.text);
// }
// comboBoxEl.classList.add(COMBO_BOX_PRISTINE_CLASS);
// return;
// }
// }
//}
for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
const optionEl = selectEl.options[i];
if ((!selectValue && !optionEl.value) || optionEl.value === selectValue) {
if (inputValue !== optionEl.text) {
changeElementValue(inputEl, optionEl.text);
}
comboBoxEl.classList.add(COMBO_BOX_PRISTINE_CLASS);
return;
}
if (selectValue) {
for (let i = 0, len = selectEl.options.length; i < len; i += 1) {
const optionEl = selectEl.options[i];
if (optionEl.value === selectValue) {
if (inputValue !== optionEl.text) {
changeElementValue(inputEl, optionEl.text);
}
comboBoxEl.classList.add(COMBO_BOX_PRISTINE_CLASS);
return;
}
}
}
if (inputValue) {
changeElementValue(inputEl);

View file

@ -31,7 +31,7 @@ initializeUrbanizationToggle();
userProfileListener();
finishUserSetupListener();
loadInitialValuesForComboBoxes();
//loadInitialValuesForComboBoxes();
handleRequestingEntityFieldset();

View file

@ -77,6 +77,20 @@ class RequestingEntityForm(RegistrarForm):
(obj.id, str(obj)) for obj in queryset
] + [("other", "Other (enter your suborganization manually)")]
@classmethod
def from_database(cls, obj: DomainRequest | None):
"""Returns a dict of form field values gotten from `obj`.
Overrides RegistrarForm method in order to set sub_organization to 'other'
on GETs of the RequestingEntityForm."""
if obj is None:
return {}
# get the domain request as a dict, per usual method
domain_request_dict = {name: getattr(obj, name) for name in cls.declared_fields.keys()} # type: ignore
# set sub_organization to 'other' if is_requesting_new_suborganization is True
if obj.is_requesting_new_suborganization():
domain_request_dict["sub_organization"] = "other"
return domain_request_dict
def clean_sub_organization(self):
"""On suborganization clean, set the suborganization value to None if the user is requesting
a custom suborganization (as it doesn't exist yet)"""
@ -102,42 +116,132 @@ class RequestingEntityForm(RegistrarForm):
)
return name
# def full_clean(self):
# """Validation logic to remove the custom suborganization value before clean is triggered.
# Without this override, the form will throw an 'invalid option' error."""
# # Remove the custom other field before cleaning
# data = self.data.copy() if self.data else None
# # Remove the 'other' value from suborganization if it exists.
# # This is a special value that tracks if the user is requesting a new suborg.
# suborganization = self.data.get("portfolio_requesting_entity-sub_organization")
# if suborganization and "other" in suborganization:
# data["portfolio_requesting_entity-sub_organization"] = ""
# # Set the modified data back to the form
# self.data = data
# # Call the parent's full_clean method
# super().full_clean()
def full_clean(self):
"""Validation logic to remove the custom suborganization value before clean is triggered.
"""Validation logic to temporarily remove the custom suborganization value before clean is triggered.
Without this override, the form will throw an 'invalid option' error."""
# Remove the custom other field before cleaning
data = self.data.copy() if self.data else None
logger.debug("full_clean")
# Ensure self.data is not None before proceeding
if self.data:
# handle case where form has been submitted
logger.debug("form was submitted")
# Create a copy of the data for manipulation
data = self.data.copy()
# Remove the 'other' value from suborganization if it exists.
# This is a special value that tracks if the user is requesting a new suborg.
suborganization = self.data.get("portfolio_requesting_entity-sub_organization")
if suborganization and "other" in suborganization:
data["portfolio_requesting_entity-sub_organization"] = ""
# Retrieve sub_organization
suborganization = data.get("portfolio_requesting_entity-sub_organization")
# Set the modified data back to the form
self.data = data
logger.debug(f"suborganization submitted as {suborganization}")
# # Determine if "other" should be stored in _original_suborganization
# if not suborganization:
# logger.debug("suborg stored as other")
# self._original_suborganization = "other"
# else:
self._original_suborganization = suborganization
# If the original value was "other", clear it for validation
if self._original_suborganization == "other":
data["portfolio_requesting_entity-sub_organization"] = ""
# Set the modified data back to the form
self.data = data
else:
# handle case of a GET
suborganization = None
if self.initial and "sub_organization" in self.initial:
print("suborg in self.initial")
suborganization = self.initial["sub_organization"]
print(self.initial["sub_organization"])
print(suborganization)
# Check if is_requesting_new_suborganization is True
is_requesting_new_suborganization = False
if self.initial and "is_requesting_new_suborganization" in self.initial:
# Call the method if it exists
print(self.initial["is_requesting_new_suborganization"]())
is_requesting_new_suborganization = self.initial["is_requesting_new_suborganization"]()
# Determine if "other" should be set
if is_requesting_new_suborganization and suborganization is None:
print("presetting to other")
self._original_suborganization = "other"
else:
self._original_suborganization = suborganization
print("self.data does not exist")
print(self.initial)
# # Handle the initial GET request case
# self._original_suborganization = None
# Call the parent's full_clean method
super().full_clean()
# Restore "other" if there are errors
if self.errors:
logger.debug(f"errors detected: {self.errors}; resetting original_sub_organization")
self.data["portfolio_requesting_entity-sub_organization"] = self._original_suborganization
# def clean(self):
# """Custom clean implementation to handle our desired logic flow for suborganization.
# Given that these fields often rely on eachother, we need to do this in the parent function."""
# cleaned_data = super().clean()
# # Do some custom error validation if the requesting entity is a suborg.
# # Otherwise, just validate as normal.
# suborganization = self.cleaned_data.get("sub_organization")
# is_requesting_new_suborganization = self.cleaned_data.get("is_requesting_new_suborganization")
# # Get the value of the yes/no checkbox from RequestingEntityYesNoForm.
# # Since self.data stores this as a string, we need to convert "True" => True.
# requesting_entity_is_suborganization = self.data.get(
# "portfolio_requesting_entity-requesting_entity_is_suborganization"
# )
# if requesting_entity_is_suborganization == "True":
# if is_requesting_new_suborganization:
# # Validate custom suborganization fields
# if not cleaned_data.get("requested_suborganization") and "requested_suborganization" not in self.errors:
# self.add_error("requested_suborganization", "Enter the name of your suborganization.")
# if not cleaned_data.get("suborganization_city"):
# self.add_error("suborganization_city", "Enter the city where your suborganization is located.")
# if not cleaned_data.get("suborganization_state_territory"):
# self.add_error(
# "suborganization_state_territory",
# "Select the state, territory, or military post where your suborganization is located.",
# )
# elif not suborganization:
# self.add_error("sub_organization", "Suborganization is required.")
# return cleaned_data
def clean(self):
"""Custom clean implementation to handle our desired logic flow for suborganization.
Given that these fields often rely on eachother, we need to do this in the parent function."""
"""Custom clean implementation to handle our desired logic flow for suborganization."""
cleaned_data = super().clean()
# Do some custom error validation if the requesting entity is a suborg.
# Otherwise, just validate as normal.
suborganization = self.cleaned_data.get("sub_organization")
is_requesting_new_suborganization = self.cleaned_data.get("is_requesting_new_suborganization")
# Get the value of the yes/no checkbox from RequestingEntityYesNoForm.
# Since self.data stores this as a string, we need to convert "True" => True.
# Get the cleaned data
suborganization = cleaned_data.get("sub_organization")
is_requesting_new_suborganization = cleaned_data.get("is_requesting_new_suborganization")
requesting_entity_is_suborganization = self.data.get(
"portfolio_requesting_entity-requesting_entity_is_suborganization"
)
if requesting_entity_is_suborganization == "True":
if is_requesting_new_suborganization:
# Validate custom suborganization fields
if not cleaned_data.get("requested_suborganization") and "requested_suborganization" not in self.errors:
self.add_error("requested_suborganization", "Enter the name of your suborganization.")
if not cleaned_data.get("suborganization_city"):
@ -150,6 +254,12 @@ class RequestingEntityForm(RegistrarForm):
elif not suborganization:
self.add_error("sub_organization", "Suborganization is required.")
# If there are errors, restore the "other" value for rendering
if self.errors and getattr(self, "_original_suborganization", None) == "other":
self.cleaned_data["sub_organization"] = self._original_suborganization
elif not self.data and getattr(self, "_original_suborganization", None) == "other":
self.cleaned_data["sub_organization"] = self._original_suborganization
return cleaned_data

View file

@ -368,7 +368,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
and from the database if `use_db` is True (provided that record exists).
An empty form will be provided if neither of those are true.
"""
logger.debug(f"get_forms({step},{use_post},{use_db},{files})")
kwargs = {
"files": files,
"prefix": self.steps.current,
@ -385,6 +385,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
for form in forms:
data = form.from_database(self.domain_request) if self.has_pk() else None
logger.debug(data)
if use_post:
instantiated.append(form(self.request.POST, **kwargs))
elif use_db:
@ -562,6 +563,13 @@ class RequestingEntity(DomainRequestWizard):
template_name = "domain_request_requesting_entity.html"
forms = [forms.RequestingEntityYesNoForm, forms.RequestingEntityForm]
#for debugging:
def get(self, request, *args, **kwargs):
"""This method handles GET requests."""
logger.debug("in get")
return super().get(request, *args, **kwargs)
def save(self, forms: list):
"""Override of save to clear or associate certain suborganization data
depending on what the user wishes to do. For instance, we want to add a suborganization