feat: hydrate select component properly
This commit is contained in:
1 parent
956c653e28
commit
b11ad5ffff
3 files changed
+57
-44
No files matched your search
@@ -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>
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user