Skip to main content

vertigo_forms/select/
dict_select.rs

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