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 yew::{Component, ComponentLink, Html, html, Properties, InputData, Callback, ShouldRender}; use crate::form::{Form}; use crate::{Model}; use crate::form_field::FormField; pub enum FieldMessage { OnInput(InputData) } fn default_text() -> String { String::from("text") } #[derive(Properties, PartialEq, Clone)] pub struct FieldProperties<T: Model> { #[prop_or_else(default_text)] pub input_type: String, pub field_name: String, pub form: Form<T>, #[prop_or_else(String::new)] pub placeholder: String, #[prop_or_else(Callback::noop)] pub oninput: Callback<InputData>, } pub struct Field<T: Model> { link: ComponentLink<Self>, pub input_type: String, pub field_name: String, pub form: Form<T>, pub placeholder: String, pub oninput: Callback<InputData>, } impl<T: Model> Field<T> { fn field(&self) -> &FormField { self.form.field(&self.field_name) } pub fn field_name(&self) -> &str { &self.field_name } pub fn class(&self) -> &str { let field = self.field(); if field.dirty && field.valid { "form-control is-valid" } else if field.dirty { "form-control is-invalid" } else { "form-control" } } pub fn message(&self) -> &str { &self.form.field_message(&self.field_name()) } pub fn valid(&self) -> bool { self.form.field_valid(&self.field_name()) } pub fn dirty(&self) -> bool { self.field().dirty } pub fn set_field(&mut self, field_name: &str, value: &str) { self.form.set_field_value(field_name, value) } } impl<T: Model> Component for Field<T> { type Message = FieldMessage; type Properties = FieldProperties<T>; fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self { let mut form_field = Self { link, input_type: String::from(props.input_type), field_name: String::from(props.field_name), form: props.form, placeholder: String::from(props.placeholder), oninput: props.oninput, }; if form_field.input_type == "" { form_field.input_type = String::from("text"); } form_field } fn update(&mut self, msg: Self::Message) -> ShouldRender { match msg { FieldMessage::OnInput(input_data) => { let state = self.form.state_mut(); state.set_field_value(&self.field_name, &input_data.value); state.update_validation(); self.oninput.emit(input_data); true } } } fn change(&mut self, _props: Self::Properties) -> ShouldRender { true } fn view(&self) -> Html { html! { <input class=self.class() id=self.field_name type=self.input_type placeholder=self.placeholder value=self.form.field_value(&self.field_name) oninput=self.link.callback(|e: InputData| FieldMessage::OnInput(e)) /> } } }