Continue validation feature

This commit is contained in:
Thomas Gideon 2021-11-07 11:54:06 -05:00
parent bff36b0ce3
commit 0ff7d59f63
6 changed files with 116 additions and 24 deletions

View File

@ -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 {
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! {
<form>
{ for self.props.children.iter() }
</form>
};
render::render_with_prefix(&self.props, "form", form)
}
#[cfg(feature = "validate")]
fn view(&self) -> Html {
let form = html! {
<form>
{ for self.props.children.iter() }
</form>
};
render::render_with_prefix(&self.props, "form", form)
}
}

View File

@ -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! {
<div>
{ for (&self.props.children).iter() }
{ super::render_validation_feedback(&self.props.error_code, &self.props.errors) }
</div>
};
render::render_with_prefix(&self.props, "input-group", div)
}
}

View File

@ -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! {
<>
<input
type=input_type
value=&self.state
readonly=self.props.readonly
onchange=self.link.callback(|evt| InputChange(evt))
/>
{ crate::input::render_validation_feedback_from_props(&self.props) }
</>
};
render::render_with_prefix(&self.props, prefix, html)
}
}
#[cfg(feature = "validate")]
fn render_validation_feedback<S: AsRef<str>>(field: S, errors: &Option<ValidationErrors>) -> Html {
if let Some(ref errors) = errors {
pub fn render_validation_feedback(
error_key: &Option<String>,
errors: &Option<ValidationErrors>,
) -> 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<S: AsRef<str>>(field: S, errors: &Option<Validatio
html! {}
}
}
#[cfg(feature = "validate")]
fn render_validation_feedback_from_props(props: &Props) -> Html {
if let Some(error_code) = props.error_code.as_ref() {
render_validation_feedback(error_code, &props.errors)
} else {
html! {}
}
}

View File

@ -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<InputType>,
// optional validation support
#[cfg(feature = "validate")]
#[prop_or_default]
pub error_code: Option<String>,
#[cfg(feature = "validate")]
#[prop_or_default]
pub errors: Option<ValidationErrors>,
// bootstrap specific
#[prop_or_default]
pub border: Option<Border>,

View File

@ -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<Self>,
state: String,
props: Props,
#[cfg(feature = "validator")]
errors: Option<ValidationErrors>,
}
#[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>) -> Self {
let state = extract_state(&props);
Self { props, state, link }
}
#[cfg(feature = "validate")]
fn create(props: Self::Properties, link: ComponentLink<Self>) -> 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 }
<textarea
readonly=self.props.readonly
onchange=self.link.callback(|evt| InputChange(evt))
>
{ &self.state }
</textarea>
{ super::render_validation_feedback_from_props(&self.props) }
</>
}
};

View File

@ -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<String>,
#[cfg(feature = "validate")]
#[prop_or_default]
pub errors: Option<ValidationErrors>,
// bootstrap specific
#[prop_or_default]
pub border: Option<Border>,