diff --git a/src/form/mod.rs b/src/form/mod.rs index 6e822e0..3e46d8b 100644 --- a/src/form/mod.rs +++ b/src/form/mod.rs @@ -21,7 +21,49 @@ impl Component for FormGroup { render_if_ne(&mut self.props, props) } + #[cfg(not(feature = "validate"))] fn view(&self) -> Html { render::render_with_prefix(&self.props, "form-group", render::div(&self.props.children)) } } + +pub struct Form { + pub props: Props, +} + +impl Component for Form { + type Message = (); + type Properties = Props; + + fn create(props: Self::Properties, _: ComponentLink) -> Self { + Self { props } + } + + fn update(&mut self, _: Self::Message) -> ShouldRender { + false + } + + fn change(&mut self, props: Self::Properties) -> ShouldRender { + render_if_ne(&mut self.props, props) + } + + #[cfg(not(feature = "validate"))] + fn view(&self) -> Html { + let form = html! { +
+ { for self.props.children.iter() } +
+ }; + render::render_with_prefix(&self.props, "form", form) + } + + #[cfg(feature = "validate")] + fn view(&self) -> Html { + let form = html! { +
+ { for self.props.children.iter() } +
+ }; + render::render_with_prefix(&self.props, "form", form) + } +} diff --git a/src/input/group.rs b/src/input/group.rs index e5a6e31..344a94b 100644 --- a/src/input/group.rs +++ b/src/input/group.rs @@ -21,6 +21,7 @@ impl Component for InputGroup { render_if_ne(&mut self.props, props) } + #[cfg(not(feature = "validate"))] fn view(&self) -> Html { render::render_with_prefix( &self.props, @@ -28,4 +29,15 @@ impl Component for InputGroup { render::div(&self.props.children), ) } + + #[cfg(feature = "validate")] + fn view(&self) -> Html { + let div = html! { +
+ { for (&self.props.children).iter() } + { super::render_validation_feedback(&self.props.error_code, &self.props.errors) } +
+ }; + render::render_with_prefix(&self.props, "input-group", div) + } } diff --git a/src/input/mod.rs b/src/input/mod.rs index ddab7a3..14f0519 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -66,6 +66,7 @@ impl Component for Input { render_if_ne(&mut self.props, props) } + #[cfg(not(feature = "validate"))] fn view(&self) -> Html { let input_type = self.props.input_type.as_ref().unwrap_or(&InputType::Text); let mut prefix = if self.props.readonly { @@ -84,11 +85,40 @@ impl Component for Input { }; render::render_with_prefix(&self.props, prefix, html) } + + #[cfg(feature = "validate")] + fn view(&self) -> Html { + let input_type = self.props.input_type.as_ref().unwrap_or(&InputType::Text); + let mut prefix = if self.props.readonly { + vec!["form-control-plaintext"] + } else { + vec!["form-control"] + }; + prefix.push(valid_as_class(&self.props.valid)); + let html = html! { + <> + + { crate::input::render_validation_feedback_from_props(&self.props) } + + }; + render::render_with_prefix(&self.props, prefix, html) + } } #[cfg(feature = "validate")] -fn render_validation_feedback>(field: S, errors: &Option) -> Html { - if let Some(ref errors) = errors { +pub fn render_validation_feedback( + error_key: &Option, + errors: &Option, +) -> Html { + // TODO keep chipping away + if error_key.is_none { + html! {} + } else if let Some(ref errors) = errors { let errors = errors.field_errors(); if let Some(errors) = errors.get(field.as_ref()) { html! { @@ -103,3 +133,12 @@ fn render_validation_feedback>(field: S, errors: &Option Html { + if let Some(error_code) = props.error_code.as_ref() { + render_validation_feedback(error_code, &props.errors) + } else { + html! {} + } +} diff --git a/src/input/props.rs b/src/input/props.rs index 68e1da7..b233fe5 100644 --- a/src/input/props.rs +++ b/src/input/props.rs @@ -4,6 +4,8 @@ use crate::{ props::{add_opt_attr, collect_props, BootstrapProps}, }; use std::collections::HashMap; +#[cfg(feature = "validate")] +use validator::ValidationErrors; use yew::{html::Children, prelude::*}; #[derive(Properties, Clone, PartialEq)] @@ -22,6 +24,14 @@ pub struct Props { #[prop_or_default] pub input_type: Option, + // optional validation support + #[cfg(feature = "validate")] + #[prop_or_default] + pub error_code: Option, + #[cfg(feature = "validate")] + #[prop_or_default] + pub errors: Option, + // bootstrap specific #[prop_or_default] pub border: Option, diff --git a/src/input/textarea.rs b/src/input/textarea.rs index 1f81ebd..16eed41 100644 --- a/src/input/textarea.rs +++ b/src/input/textarea.rs @@ -1,15 +1,11 @@ use super::props::Props; use crate::{prelude::*, render}; -#[cfg(feature = "validate")] -use validator::ValidationErrors; use yew::{prelude::*, virtual_dom::VNode}; pub struct TextArea { link: ComponentLink, state: String, props: Props, - #[cfg(feature = "validator")] - errors: Option, } #[derive(Debug)] @@ -19,23 +15,11 @@ impl Component for TextArea { type Message = InputChange; type Properties = Props; - #[cfg(not(feature = "validate"))] fn create(props: Self::Properties, link: ComponentLink) -> Self { let state = extract_state(&props); Self { props, state, link } } - #[cfg(feature = "validate")] - fn create(props: Self::Properties, link: ComponentLink) -> Self { - let state = extract_state(&props); - Self { - props, - state, - link, - errors: None, - } - } - fn update(&mut self, msg: Self::Message) -> ShouldRender { if let InputChange(ChangeData::Value(value)) = msg { self.state = value.clone(); @@ -73,21 +57,16 @@ impl Component for TextArea { #[cfg(feature = "validate")] fn view(&self) -> Html { let prefix = vec!["form-control", &valid_as_class(&self.props.valid)]; - let feedback = if let Some(name) = self.props.name.as_ref() { - super::render_validation_feedback(name, &self.errors) - } else { - html! {} - }; let html = { html! { <> - { feedback } + { super::render_validation_feedback_from_props(&self.props) } } }; diff --git a/src/props.rs b/src/props.rs index 90f7cc7..48a313f 100644 --- a/src/props.rs +++ b/src/props.rs @@ -1,5 +1,7 @@ use crate::prelude::*; use std::collections::HashMap; +#[cfg(feature = "validate")] +use validator::ValidationErrors; use yew::{prelude::*, virtual_dom::VNode}; pub(crate) trait IntoBsClass { @@ -32,6 +34,14 @@ pub struct Props { #[prop_or_default] pub children: Children, + // optional validation support + #[cfg(feature = "validate")] + #[prop_or_default] + pub error_code: Option, + #[cfg(feature = "validate")] + #[prop_or_default] + pub errors: Option, + // bootstrap specific #[prop_or_default] pub border: Option,