diff --git a/src/components/typeahead_input.rs b/src/components/typeahead_input.rs
index 53b9f45..f4d6048 100644
--- a/src/components/typeahead_input.rs
+++ b/src/components/typeahead_input.rs
@@ -8,6 +8,8 @@ use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
use leptos::logging::log;
use std::time::Duration;
+use std::rc::Rc;
+use std::cell::RefCell;
#[component]
pub fn TypeaheadInput(
@@ -20,14 +22,42 @@ pub fn TypeaheadInput(
) -> impl IntoView {
let (is_initialized, set_initialized) = create_signal(false);
+ // Flag to track if component is mounted
+ let is_mounted = Rc::new(RefCell::new(true));
+ let is_mounted_clone = is_mounted.clone();
+
+ // Cleanup function to run when component is unmounted
+ on_cleanup(move || {
+ log!("[CLEANUP] TypeaheadInput component unmounting");
+ *is_mounted_clone.borrow_mut() = false;
+ });
+
+ // Clone necessary values for the async task
+ let fetch_suggestions_clone = fetch_suggestions.clone();
+ let on_select_clone = on_select.clone();
+ let node_ref_clone = node_ref.clone();
+
spawn_local(async move {
log!("[INIT] Component mounted");
let mut retries = 0;
while retries < 10 {
- if let Some(input) = node_ref.get() {
+ // Check if component is still mounted before proceeding
+ if !*is_mounted.borrow() {
+ log!("[INIT] Component unmounted, aborting initialization");
+ return;
+ }
+
+ if let Some(input) = node_ref_clone.get() {
log!("[INIT] Input element found");
- let bloodhound = initialize_bloodhound(fetch_suggestions.clone());
+
+ // Only proceed if component is still mounted
+ if !*is_mounted.borrow() {
+ log!("[INIT] Component unmounted after input found, aborting");
+ return;
+ }
+
+ let bloodhound = initialize_bloodhound(fetch_suggestions_clone.clone());
// Store bloodhound globally
js_sys::Reflect::set(
@@ -36,70 +66,84 @@ pub fn TypeaheadInput(
&bloodhound
).unwrap();
- initialize_typeahead(&input, bloodhound, on_select.clone(), node_ref.clone());
- set_initialized.set(true);
+ // Only proceed if component is still mounted
+ if !*is_mounted.borrow() {
+ log!("[INIT] Component unmounted before typeahead init, aborting");
+ return;
+ }
+
+ initialize_typeahead(&input, bloodhound, on_select_clone.clone(), node_ref_clone.clone());
+
+ // Only set initialized if component is still mounted
+ if *is_mounted.borrow() {
+ set_initialized.set(true);
+ }
break;
}
+
gloo_timers::future::sleep(Duration::from_millis(100)).await;
retries += 1;
}
});
+ // CSS
+ let css = r#"
+ .typeahead.tt-input {
+ background: transparent !important;
+ }
+
+ .tt-menu {
+ width: 100% !important;
+ background: white;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ box-shadow: 0 5px 10px rgba(0,0,0,.2);
+ max-height: 300px;
+ overflow-y: auto;
+ z-index: 1000 !important;
+ }
+
+ .tt-dataset-suggestions {
+ padding: 8px 0;
+ }
+
+ .suggestion-item * {
+ pointer-events: none; /* Prevent element interception */
+ white-space: nowrap; /* Prevent text wrapping */
+ overflow: hidden; /* Hide overflow */
+ text-overflow: ellipsis; /* Add ellipsis for long text */
+ }
+
+ .suggestion-item {
+ padding: 8px 15px;
+ border-bottom: 1px solid #eee;
+ }
+
+ .suggestion-item:hover {
+ background-color: #f8f9fa;
+ cursor: pointer;
+ }
+
+ .label {
+ font-weight: 500;
+ color: #333;
+ }
+
+ .description {
+ font-size: 0.9em;
+ color: #666;
+ margin-top: 2px;
+ }
+
+ .empty-suggestion {
+ padding: 8px 15px;
+ color: #999;
+ }
+ "#;
+
view! {