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
#[macro_use] extern crate plaster; pub mod fields; use plaster::prelude::*; pub trait Form { type Value: Clone; fn value(&self) -> Self::Value; } #[derive(Clone, Default, PartialEq)] pub struct TestValue { name: String, } pub struct TestForm { value: TestValue, submit_label: Option<String>, on_change: Option<Callback<TestValue>>, on_submit: Option<Callback<TestValue>>, } #[derive(Clone, Default, PartialEq)] pub struct TestFormProps { default_value: Option<TestValue>, submit_label: Option<String>, on_change: Option<Callback<TestValue>>, on_submit: Option<Callback<TestValue>>, } pub enum TestFormMessage { UpdateName(String), Submit, } impl Component for TestForm { type Message = TestFormMessage; type Properties = TestFormProps; fn create(props: Self::Properties, _: ComponentLink<Self>) -> TestForm { TestForm { value: props.default_value.unwrap_or(TestValue::default()), submit_label: props.submit_label, on_change: props.on_change, on_submit: props.on_submit, } } fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { TestFormMessage::UpdateName(value) => { self.value.name = value; if let Some(ref callback) = self.on_change { callback.emit(self.value.clone()); } true } TestFormMessage::Submit => { if let Some(ref callback) = self.on_submit { callback.emit(self.value.clone()); } false } } } } impl Renderable<TestForm> for TestForm { fn view(&self) -> Html<Self> { html! { <form onsubmit=|e| { e.prevent_default(); TestFormMessage::Submit },> <fields::text::TextField: label="Name", on_change=|v| TestFormMessage::UpdateName(v), /> <button>{self.submit_label.as_ref().map(|s| s.as_str()).unwrap_or("Submit")}</button> </form> } } } impl Form for TestForm { type Value = TestValue; fn value(&self) -> Self::Value { self.value.clone() } }