Dynamic Autocomplete Configuration Number of autocomplete sections: 2 Section 1 Name: Billing Allowed States: CA Section 2 Name: Mailing Allowed States: CA const autocompleteConfig = [ { "autocompleteInputId": "billing_ac", "ALLOWED_STATES": [ "CA" ], "ADDRESS_INPUT_IDS": { "street": "billing-street_ac", "city": "billing-city_ac", "zip": "billing-zip_ac", "state": "billing-state_ac", "county": "billing-county_ac", "apt": "billing-apt_ac" } }, { "autocompleteInputId": "mailing_ac", "ALLOWED_STATES": [ "CA" ], "ADDRESS_INPUT_IDS": { "street": "mailing-street_ac", "city": "mailing-city_ac", "zip": "mailing-zip_ac", "state": "mailing-state_ac", "county": "mailing-county_ac", "apt": "mailing-apt_ac" } } ]; injectCSS(autocompleteConfig); var SESSION_TOKEN = getUUIDv4(); var API_ENDPOINT = 'https://n8n.civiq.io/webhook/auto6a66eb68-b3c0-45dd-a930-8cf43ef28570?session_token=' + SESSION_TOKEN; var observer; document.addEventListener("DOMContentLoaded", function() { initializeAutocomplete(); observeFormChanges(); }); function observeFormChanges() { var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes.length) { initializeAutocomplete(); } }); }); observer.observe(document.body, { childList: true, subtree: true }); } function initializeAutocomplete() { autocompleteConfig.forEach(function(config) { var inputElement = document.querySelector('[aria-label="' + config.autocompleteInputId + '"]'); if (inputElement && !inputElement.classList.contains("autocomplete-initialized")) { console.log("creating autocomplete"); createAddressAutocomplete(config); injectCSS([config]); // Inject CSS for this config only if the element exists } }); } function createAddressAutocomplete(config) { var inputElement = document.querySelector('[aria-label="' + config.autocompleteInputId + '"]'); if (inputElement) { inputElement.classList.add("autocomplete-initialized"); var addressAutocomplete = new AddressAutocomplete({ ...config, API_ENDPOINT: API_ENDPOINT, }); } } class AddressAutocomplete { constructor(config) { this.config = config; this.dropdownElement = null; this.init(); } init() { this.inputElement = document.querySelector('[aria-label="' + this.config.autocompleteInputId + '"]'); if (!this.inputElement) return; this.createDropdownElement(); this.addEventListeners(); } createDropdownElement() { this.dropdownElement = document.createElement("div"); this.dropdownElement.id = "suggestions-dropdown"; this.dropdownElement.style.display = "none"; document.body.appendChild(this.dropdownElement); } addEventListeners() { this.inputElement.addEventListener( "input", this.debounce(this.fetchSuggestions.bind(this), 300) ); window.addEventListener("resize", this.repositionDropdown.bind(this)); document.addEventListener("click", function(event) { if ( !this.dropdownElement.contains(event.target) && event.target !== this.inputElement ) { this.dropdownElement.style.display = "none"; } }.bind(this)); } async fetchSuggestions(e) { var value = e.target.value; if (!value) { this.dropdownElement.style.display = "none"; return; } try { var response = await fetch( this.config.API_ENDPOINT + '&input=' + encodeURIComponent(value) ); console.log("Fetching suggestions"); if (!response.ok) throw new Error("Failed to fetch"); var suggestions = await response.json(); var filteredSuggestions = suggestions.filter(function(suggestion) { return this.config.ALLOWED_STATES?.includes(suggestion.state); }.bind(this)); this.updateDropdown(filteredSuggestions); } catch (error) { console.error("Error fetching address suggestions:", error); this.dropdownElement.style.display = "none"; } } updateDropdown(suggestions) { this.dropdownElement.innerHTML = ""; suggestions.forEach(function(suggestion) { var div = document.createElement("div"); div.className = "suggestion-item"; var addressLine = '