vertigo_forms/select/
dict_select.rs

1use vertigo::{AttrGroup, Computed, Value, bind, component, computed_tuple, dom};
2
3/// Simple Select component based on map of `i64`->`T` values.
4///
5/// Example:
6/// ```
7/// use vertigo::{DomNode, dom, Value};
8/// use vertigo_forms::DictSelect;
9///
10/// let value = Value::new(1);
11/// let options = Value::new(
12///     vec![
13///         (1, "foo".to_string()),
14///         (2, "bar".to_string()),
15///         (3, "baz".to_string()),
16///     ]
17/// );
18///
19/// dom! {
20///     <DictSelect
21///         value={value.clone()}
22///         options={options}
23///     />
24/// };
25/// ```
26#[component]
27pub fn DictSelect<T: Clone + From<String> + PartialEq + ToString + 'static>(
28    value: Value<i64>,
29    options: Computed<Vec<(i64, T)>>,
30    select: AttrGroup,
31) {
32    let on_change = bind!(value, |new_value: String| {
33        value.set(new_value.parse().unwrap_or_default());
34    });
35
36    // Generate empty option only if initial value does not match any of provided options
37    let empty = computed_tuple!(value, options).render_value_option(|(value, options)| {
38        options
39            .iter()
40            .all(|(key, _)| key != &value)
41            .then(|| dom! { <option value="" selected="selected" /> })
42    });
43
44    let list = bind!(
45        options,
46        value.render_value(move |value| options.render_list(
47            |(key, _)| key.to_string(),
48            move |(key, item)| {
49                let text_item = item.to_string();
50                if key == &value {
51                    dom! { <option value={&key} selected="selected">{text_item}</option> }
52                } else {
53                    dom! { <option value={&key}>{text_item}</option> }
54                }
55            }
56        ))
57    );
58
59    dom! {
60        <select {on_change} {..select}>
61            {empty}
62            {list}
63        </select>
64    }
65}