nova_forms/components/
select.rsuse std::{fmt::Display, hash::Hash, str::FromStr};
use crate::{use_translation, QueryString, FieldWiring};
use html::Select;
use leptos::*;
use strum::{IntoEnumIterator, ParseError};
#[component]
pub fn Select<T>(
#[prop(into)] label: TextProp,
#[prop(into)] bind: QueryString,
#[prop(optional, into)] value: MaybeProp<T>,
#[prop(optional, into)] change: Option<Callback<Result<T, T::Err>, ()>>,
#[prop(optional, into)] error: MaybeProp<TextProp>,
) -> impl IntoView
where
T: IntoEnumIterator + FromStr<Err = ParseError> + Into<&'static str> + Clone + Copy + Default + Eq + Hash + Display + 'static
{
let FieldWiring {
qs,
value,
raw_value,
error,
set_raw_value,
render_mode,
..
} = FieldWiring::<T>::wire(label.clone(), bind, value, change, error);
let node_ref = NodeRef::<Select>::new();
node_ref.on_load(move |element| {
let element: &web_sys::HtmlSelectElement = &*element;
let value = element.value();
if !value.is_empty() {
set_raw_value.call(value);
}
});
view! {
<div
class="field select"
class:error=move || error.get().is_some()
class:ok=move || error.get().is_none()
>
<label for=qs.to_string()>{label}</label>
{move || {
let qs = qs.clone();
if render_mode.get() {
let text_elem = html::input()
.attr("type", "text")
.attr("readonly", true)
.attr("id", qs.to_string())
.attr("name", qs.to_string())
.attr("value", move || raw_value.get());
text_elem.into_view()
} else {
view! {
<select _ref=node_ref id=qs.to_string() name=qs.to_string() on:input=move |ev| {
set_raw_value.call(event_target_value(&ev));
}>
<For
each={move || T::iter()}
key={|item| *item}
children={move |item| {
let option_elem = html::option()
.attr("id", format!("{}({})", qs.to_string(), item.into()))
.attr("selected", move || value.get() == Ok(item))
.attr("value", move || item.into())
.child(use_translation(item));
view! {
{option_elem}
}
}}
/>
</select>
}.into_view()
}
}}
{move || {
if let Some(error) = error.get() {
view! { <span class="error-message">{error}</span> }
.into_view()
} else
if let Some(error) = error.get() {
view! { <span class="error-message">{error}</span> }
.into_view()
} else {
View::default()
}
}}
</div>
}
}