Skip to main content

vertigo_forms/select/
select.rs

1use std::ops::Not;
2
3use vertigo::{Computed, DomNode, Value, bind, computed_tuple, dom, render::render_list};
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 + PartialEq + 'static> {
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 = render_list(options, |item| item.to_string(), {
55            let value = value.clone();
56            move |item: &Computed<T>| {
57                let item = item.clone();
58                let text_item = item.map(|item| item.to_string());
59                let selected = computed_tuple!(item, value)
60                    .map(|(item, value)| (item == value).then(|| "selected".to_string()));
61                dom! { <option value={&text_item} {selected}>{text_item}</option> }
62            }
63        });
64
65        dom! {
66            <select {on_change}>
67                {empty}
68                {list}
69            </select>
70        }
71    }
72}