nova_forms/components/
input.rs

1use crate::{Datatype, QueryString, FieldWiring};
2use leptos::*;
3
4/// A component that renders an input field.
5/// It takes a datatype as a type parameter and automatically handles parsing and validation.
6#[component]
7pub fn Input<T>(
8    /// The label of the input field.
9    #[prop(into)] label: TextProp,
10    /// The query string that binds the input field to the form data.
11    #[prop(into)] bind: QueryString,
12    /// The placeholder text of the input field.
13    #[prop(optional, into)] placeholder: Option<T>,
14    /// The initial value of the input field.
15    #[prop(optional, into)] value: MaybeProp<T>,
16    /// A write signal that is updated with the parsed value of the input field.
17    #[prop(optional, into)] change: Option<Callback<Result<T, T::Error>, ()>>,
18    /// Set a custom error message for the input field.
19    #[prop(optional, into)] error: MaybeProp<TextProp>,
20) -> impl IntoView
21where
22    T: Datatype,
23{    
24    let FieldWiring {
25        qs,
26        raw_value,
27        error,
28        set_raw_value,
29        render_mode,
30        ..
31    } = FieldWiring::wire(bind, value, change, error);
32
33    // Get value on load from the input field.
34    let node_ref = NodeRef::new();
35    node_ref.on_load(move |element| {
36        let element: &web_sys::HtmlInputElement = &*element;
37        let value = element.value();
38        if !value.is_empty() {
39            set_raw_value.call(value);
40        }
41    });
42
43    /*
44    let text_elem = T::attributes()
45        .into_iter()
46        .filter(|(name, _)| *name != "type")
47        .fold(html::input(), |el, (name, value)| el.attr(name, value))
48        .attr("type", "text")
49        .attr("readonly", true)
50        .attr("id", qs.to_string())
51        .attr("name", qs.to_string())
52        .prop("value", move || {
53            logging::log!("raw_value in text elem is : {:?}", raw_value.get());
54            raw_value.get()
55        });
56    */
57
58    let input_elem = T::attributes()
59        .into_iter()
60        .fold(html::input(), |el, (name, value)| el.attr(name, value))
61        .attr("id", qs.to_string())
62        .attr("name", qs.to_string())
63        .attr("placeholder", placeholder.as_ref().map(T::to_string))
64        .prop("value", move || raw_value.get())
65        .node_ref(node_ref)
66        .on(ev::input, move |ev| {
67            set_raw_value.call(event_target_value(&ev));
68        });
69
70    view! {
71        <div
72            class="field"
73            class:error=move || error.get().is_some()
74            class:ok=move || error.get().is_none()
75        >
76            {move || {
77                if render_mode.get() {
78                    view!{
79                        <span class="label">{label.clone()}</span>
80                        <span class="value">{raw_value.get()}</span>
81                    }.into_view()
82                } else {
83                    view! {
84                        <label for=qs.to_string()>{label.clone()}</label>
85                        {input_elem.clone()}
86                        {move || {
87                            if let Some(error) = error.get() {
88                                view! { <span class="error-message">{error}</span> }
89                                    .into_view()
90                            } else {
91                                View::default()
92                            }
93                        }}
94                    }.into_view()
95                }
96            }}
97        </div>
98    }
99}