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>
}
}
}