vertigo_forms/select/
select.rs

1use std::ops::Not;
2
3use vertigo::{Computed, DomNode, Value, bind, computed_tuple, dom};
4
5/// Simple Select component based on vector of `T` values.
6///
7/// Example:
8/// ```
9/// use vertigo::{DomNode, dom, Value};
10/// use vertigo_forms::Select;
11///
12/// let value = Value::new("foo".to_string());
13/// let options = Value::new(
14///     vec![
15///         "foo".to_string(),
16///         "bar".to_string(),
17///         "baz".to_string(),
18///     ]
19/// );
20///
21/// dom! {
22///     <Select
23///         value={value.clone()}
24///         options={options}
25///     />
26/// };
27/// ```
28pub struct Select<T: Clone> {
29    pub value: Value<T>,
30    pub options: Computed<Vec<T>>,
31}
32
33impl<T> Select<T>
34where
35    T: Clone + From<String> + PartialEq + ToString + 'static,
36{
37    pub fn into_component(self) -> Self {
38        self
39    }
40
41    pub fn mount(&self) -> DomNode {
42        let Self { value, options } = self;
43        let on_change = bind!(value, |new_value: String| {
44            value.set(new_value.into());
45        });
46
47        let empty = computed_tuple!(value, options).render_value_option(|(value, options)| {
48            options
49                .contains(&value)
50                .not()
51                .then(|| dom! { <option value="" selected="selected" /> })
52        });
53
54        let list = bind!(
55            options,
56            value.render_value(move |value| options.render_list(
57                |item| item.to_string(),
58                move |item| {
59                    let text_item = item.to_string();
60                    if item == &value {
61                        dom! { <option value={&text_item} selected="selected">{text_item}</option> }
62                    } else {
63                        dom! { <option value={&text_item}>{text_item}</option> }
64                    }
65                }
66            ))
67        );
68
69        dom! {
70            <select {on_change}>
71                {empty}
72                {list}
73            </select>
74        }
75    }
76}