import AddressValidator from "./AddressValidator"; import ButtonController from "./ButtonController"; /** * InputHandler class that manages the validation and input synchronization between address and house number fields. * It ensures that the address and house number fields are correctly formatted and keeps them in sync. */ class InputHandler { private $addressField: JQuery; private $houseNumberField: JQuery; private buttonController: ButtonController; private errorMessage: JQuery; /** * Constructor for the InputHandler class. * Initializes the address field, house number field, button controller, and error message span element. * * @param {string} addressFieldSelector - The selector for the address input field. * @param {string} houseNumberFieldSelector - The selector for the house number input field. */ constructor(addressFieldSelector: string, houseNumberFieldSelector: string) { this.$addressField = jQuery(addressFieldSelector); this.$houseNumberField = jQuery(houseNumberFieldSelector); this.buttonController = new ButtonController(); this.errorMessage = jQuery( '', ); this.$addressField.after(this.errorMessage); } /** * Handles input events for both the address and house number fields. * Validates the input and displays error messages or enables/disables the submit button accordingly. * * @param {InputEvent} event - The input event triggered by the user typing in the address or house number field. */ handleInput(event: InputEvent): void { // Determine which field was edited (address or house number) const field = jQuery(event.target as HTMLElement) as JQuery; // Specifieer het type van field const cleanedValue = AddressValidator.cleanInput(field.val() as string); // Clean the input value let errorMessage = ""; // Validate the input when the address field is edited if (field.is(this.$addressField)) { if ( cleanedValue !== "" && !AddressValidator.validateHouseNumberBeforeStreet(cleanedValue) ) { errorMessage = "Het huisnummer mag niet voor de straatnaam komen."; } else if ( cleanedValue !== "" && !AddressValidator.validateExtraTextAfterHouseNumber(cleanedValue) ) { errorMessage = "Er mag geen extra tekst komen na het huisnummer."; } else if ( cleanedValue !== "" && !AddressValidator.validateAddressFormat(cleanedValue) ) { errorMessage = "Het adres moet een straatnaam bevatten gevolgd door een geldig huisnummer."; } } // Re-initializing the value after cleaning field.val(cleanedValue); // Show or hide the error message based on validation results if (errorMessage) { this.errorMessage.text(errorMessage); this.buttonController.disableButton(); // Disable submit button if there's an error } else { this.errorMessage.text(""); this.buttonController.enableButton(); // Enable submit button if input is valid } // Trigger AJAX completion (re-enable/disable button based on the current validation) jQuery(document).ajaxComplete(() => { if (errorMessage) { this.buttonController.disableButton(); } else { this.buttonController.enableButton(); } }); // Handle the address-to-house number synchronization if (field.is(this.$addressField)) { this.updateHouseNumber(); } else if (field.is(this.$houseNumberField)) { this.updateStreetName(); } } /** * Updates the house number field based on the current address field value. * If a house number is found in the address, it will populate the house number field. */ updateHouseNumber(): void { const addressValue = (this.$addressField.val() as string)?.trim() || ""; // Cast to string and trim any whitespace const houseNumberMatch = addressValue.match(/(\d+[^\s]*)\s*$/); // Match house number at the end const streetName = addressValue.replace(/\d+[^\s]*\s*$/, "").trim(); // Remove the house number and extra characters // If a valid house number is found, update the house number field if (houseNumberMatch) { const validHouseNumber = houseNumberMatch[1].replace(/[^0-9a-zA-Z]/g, ""); // Remove any invalid characters from the house number this.$houseNumberField.val(validHouseNumber); } else { this.$houseNumberField.val(""); // Clear the house number field if no valid house number is found } } /** * Updates the address field based on the current house number field value. * It will prepend the house number to the street name if the house number is not empty. */ updateStreetName(): void { // Function to safely handle trimming of values that could be undefined, a number, or an array of strings const safeTrim = ( value: string | number | string[] | undefined, ): string => { if (typeof value === "string" || typeof value === "number") { return value.toString().trim(); // Convert value to string and trim any whitespace } return ""; // Return an empty string if it's neither a string nor a number }; // Get the current values of the house number and address fields const houseNumberValue = safeTrim(this.$houseNumberField.val()); // Ensures it's a string const addressValue = safeTrim(this.$addressField.val()); // Ensures it's a string let streetName = addressValue.replace(/\d+[^\s]*\s*$/, "").trim(); // Remove the house number from the address // If there's a house number, update the address field with the street name and house number if (houseNumberValue !== "") { streetName = streetName.trim(); // Ensure no extra spaces this.$addressField.val(`${streetName} ${houseNumberValue}`.trim()); } } } export default InputHandler;