feat: hydrate select component properly

This commit is contained in:
alphafetus committed 2026-02-05 00:42:55 -05:00
1 parent 956c653e28
commit b11ad5ffff
3 files changed
+57 -44

No files matched your search

+55 -43
View File
@@ -3,7 +3,7 @@ use leptos::ev::{Event, Targeted};
use leptos::prelude::*;
use leptos::web_sys::HtmlSelectElement;
use std::collections::HashMap;
use leptos::logging::{log, warn};
use leptos::logging::log;
use crate::components::{use_validation_context, InputState, ValidationState};
fn validate(required: bool, value: String) -> ValidationState {
@@ -28,28 +28,29 @@ pub fn Select(
#[prop(optional, into)] required: Signal<bool>
) -> impl IntoView {
//#region Value Logic
let default_raw_value = data_map.get_untracked()
.get(&data_member.get_untracked())
.cloned()
.unwrap_or_default()
.as_string().unwrap_or_default().unwrap_or_default();
let raw_value = RwSignal::new(default_raw_value);
Effect::new(move || {
data_map.update(|map| {
map.insert(data_member.get(), ValueType::String(Some(raw_value.get())));
});
let value = Memo::new(move |_| {
data_map.with(|map| {
map.get(&data_member.get_untracked())
.and_then(|v| v.as_string().ok().flatten())
.unwrap_or_default()
})
});
Effect::new(move || {
log!("Current select value: {}", value.get());
});
// Effect::new(move || {
// data_map.update(|map| {
// map.insert(data_member.get(), ValueType::String(Some(raw_value.get())));
// });
// });
//#endregion
//#region Validation Logic
let error = RwSignal::new(
validate(required.get_untracked(), raw_value.get_untracked())
);
warn!("Current error state: {:?}", error.get_untracked());
let error = Memo::new(move |_| validate(required.get(), value.get()));
let dirty = RwSignal::new(false);
let show_errors = Signal::derive(move || dirty.get() && matches!(error.get(), ValidationState::Invalid(_)));
@@ -68,21 +69,29 @@ pub fn Select(
//#endregion
//#region Event Logic
let on_change = move |e: Targeted<Event, HtmlSelectElement>| {
let value = e.target().value();
log!("Found value {}", value);
raw_value.set(value.clone());
error.set(validate(required.get(), raw_value.get()));
dirty.set(true);
data_map.update(|map| {
if let Some(val) = map.get_mut(&data_member.get()) {
*val = ValueType::String(Some(value.clone()));
} else {
map.insert(data_member.get(), ValueType::String(Some(value)));
}
map.insert(data_member.get(), ValueType::String(Some(value)));
});
};
// let on_change = move |e: Targeted<Event, HtmlSelectElement>| {
// let value = e.target().value();
// log!("Found value {}", value);
// raw_value.set(value.clone());
// error.set(validate(required.get(), raw_value.get()));
// dirty.set(true);
// data_map.update(|map| {
// if let Some(val) = map.get_mut(&data_member.get()) {
// *val = ValueType::String(Some(value.clone()));
// } else {
// map.insert(data_member.get(), ValueType::String(Some(value)));
// }
// });
// };
//#endregion
@@ -96,28 +105,31 @@ pub fn Select(
transition-border duration-150
border-red-700 bg-transparent
disabled:border-gray-600 disabled:pointer-events-none disabled:bg-gray-600/33"
prop:value=move || value.get()
on:change:target=on_change
disabled=disabled
>
// This closure handles the display of the options.
<option
value=""
disabled
hidden
selected=move || raw_value.get().is_empty()
>
<option value="" disabled hidden selected=move || value.get().is_empty()>
"Select one..."
</option>
{move || {
value_list
.get()
.iter()
.map(move |value| {
let display = value.to_owned();
view! { <option value=display>{display.clone()}</option> }
})
.collect::<Vec<_>>()
}}
// We can reasonably assume that the options in the list will be distinct.
<For
each=move || value_list.get()
key=|value| value.clone()
children=move |val| view! { <option value=val>{val.clone()}</option> }
/>
// {move || {
// value_list
// .get()
// .iter()
// .map(move |value| {
// let display = value.to_owned();
// view! { <option value=display>{display.clone()}</option> }
// })
// .collect::<Vec<_>>()
// }}
</select>
</label>
</div>
+1 -1
View File
@@ -194,7 +194,7 @@ fn Entry(
) -> impl IntoView {
view! {
<div class="flex flex-col flex-1 p-2 rounded-sm transition-shadow shadow-sm hover:shadow-lg/30">
{schema
{move || schema
.get()
.iter()
.map(|input_type|
+1
View File
@@ -5,6 +5,7 @@ use crate::components::{ActionButton, Header};
/// Indicates the current state of an input.
#[derive(Default, Debug, Clone)]
#[derive(PartialEq)]
pub enum ValidationState {
/// A valid input.
#[default]