1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use callback::Callback;
use html::{ChangeData, Component, ComponentLink, Html, Renderable, ShouldRender};
pub struct Select<T> {
props: Props<T>,
}
pub enum Msg {
Selected(Option<usize>),
}
#[derive(PartialEq, Clone)]
pub struct Props<T> {
pub selected: Option<T>,
pub disabled: bool,
pub options: Vec<T>,
pub onchange: Option<Callback<T>>,
}
impl<T> Default for Props<T> {
fn default() -> Self {
Props {
selected: None,
disabled: false,
options: Vec::new(),
onchange: None,
}
}
}
impl<T> Component for Select<T>
where
T: PartialEq + Clone + 'static,
{
type Message = Msg;
type Properties = Props<T>;
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
Self { props }
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
Msg::Selected(value) => {
if let Some(idx) = value {
if let Some(ref mut callback) = self.props.onchange {
let item = self.props.options.get(idx - 1).cloned();
if let Some(value) = item {
callback.emit(value);
}
}
}
}
}
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
self.props = props;
true
}
}
impl<T> Renderable<Select<T>> for Select<T>
where
T: ToString + PartialEq + Clone + 'static,
{
fn view(&self) -> Html<Self> {
let selected = self.props.selected.as_ref();
let view_option = |value: &T| {
let flag = selected == Some(value);
html! {
<option selected=flag,>{ value.to_string() }</option>
}
};
html! {
<select disabled=self.props.disabled,
onchange=|event| {
match event {
ChangeData::Select(elem) => {
let value = elem.selected_index();
Msg::Selected(if value < 0 {
None
} else {
Some(value as usize)
})
}
_ => {
unreachable!();
}
}
},>
<option disabled=true,
selected=selected.is_none(),
>{ "↪" }</option>
{ for self.props.options.iter().map(view_option) }
</select>
}
}
}