diff --git a/src/registrar/assets/js/uswds-edited.js b/src/registrar/assets/js/uswds-edited.js index 60502050f..9e3922c9c 100644 --- a/src/registrar/assets/js/uswds-edited.js +++ b/src/registrar/assets/js/uswds-edited.js @@ -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 - // comboBoxEl.insertAdjacentHTML("beforeend", Sanitizer.escapeHTML` - +   @@ -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); diff --git a/src/registrar/assets/src/js/getgov/main.js b/src/registrar/assets/src/js/getgov/main.js index 6ff402aa4..9f3156cf7 100644 --- a/src/registrar/assets/src/js/getgov/main.js +++ b/src/registrar/assets/src/js/getgov/main.js @@ -31,7 +31,7 @@ initializeUrbanizationToggle(); userProfileListener(); finishUserSetupListener(); -loadInitialValuesForComboBoxes(); +//loadInitialValuesForComboBoxes(); handleRequestingEntityFieldset(); diff --git a/src/registrar/forms/domain_request_wizard.py b/src/registrar/forms/domain_request_wizard.py index 636a41760..e40355d61 100644 --- a/src/registrar/forms/domain_request_wizard.py +++ b/src/registrar/forms/domain_request_wizard.py @@ -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 diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index 9754b0d0c..e0225aab3 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -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