From bff36b0ce3c80f3c726ce6496045955ba847e2f3 Mon Sep 17 00:00:00 2001 From: Thomas Gideon Date: Sun, 11 Apr 2021 11:29:42 -0400 Subject: [PATCH] Add validate feature --- Cargo.toml | 4 ++++ src/input/mod.rs | 26 ++++++++++++++++++++----- src/input/textarea.rs | 45 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c85f807..5912900 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,9 @@ edition = "2018" [lib] crate-type = ["cdylib", "rlib"] +[features] +validate = [ "validator" ] + [dependencies] yew = "~0.17.2" log = "~0.4.8" @@ -18,3 +21,4 @@ web-sys = "~0.3.38" wasm-logger = "~0.2.0" yew-router = "~0.14.0" yew-components = "~0.2.0" +validator = { optional = true, version = "~0.13.0" } diff --git a/src/input/mod.rs b/src/input/mod.rs index 31a57ea..ddab7a3 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -6,6 +6,8 @@ use self::props::Props; pub use self::{group::InputGroup, textarea::TextArea}; use crate::{prelude::*, render}; use std::fmt::{Display, Formatter, Result as FmtResult}; +#[cfg(feature = "validate")] +use validator::ValidationErrors; use yew::prelude::*; #[derive(Clone, PartialEq)] @@ -65,11 +67,7 @@ impl Component for Input { } fn view(&self) -> Html { - let input_type = self - .props - .input_type - .as_ref() - .unwrap_or_else(|| &InputType::Text); + 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 { @@ -87,3 +85,21 @@ impl Component for Input { 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 { + let errors = errors.field_errors(); + if let Some(errors) = errors.get(field.as_ref()) { + html! { +
+ { for errors.iter().filter_map(|error| error.message.as_ref()) } +
+ } + } else { + html! {} + } + } else { + html! {} + } +} diff --git a/src/input/textarea.rs b/src/input/textarea.rs index 06de6a8..1f81ebd 100644 --- a/src/input/textarea.rs +++ b/src/input/textarea.rs @@ -1,11 +1,15 @@ 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)] @@ -15,11 +19,23 @@ 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(); @@ -38,15 +54,42 @@ impl Component for TextArea { should_render } + #[cfg(not(feature = "validate"))] fn view(&self) -> Html { let prefix = vec!["form-control", &valid_as_class(&self.props.valid)]; - let html = html! { + let html = { + html! { + } + }; + render::render_with_prefix(&self.props, prefix, html) + } + + #[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 } + + + } }; render::render_with_prefix(&self.props, prefix, html) }