Add validate feature
This commit is contained in:
parent
2541c89161
commit
bff36b0ce3
3 changed files with 69 additions and 6 deletions
|
@ -7,6 +7,9 @@ edition = "2018"
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
validate = [ "validator" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
yew = "~0.17.2"
|
yew = "~0.17.2"
|
||||||
log = "~0.4.8"
|
log = "~0.4.8"
|
||||||
|
@ -18,3 +21,4 @@ web-sys = "~0.3.38"
|
||||||
wasm-logger = "~0.2.0"
|
wasm-logger = "~0.2.0"
|
||||||
yew-router = "~0.14.0"
|
yew-router = "~0.14.0"
|
||||||
yew-components = "~0.2.0"
|
yew-components = "~0.2.0"
|
||||||
|
validator = { optional = true, version = "~0.13.0" }
|
||||||
|
|
|
@ -6,6 +6,8 @@ use self::props::Props;
|
||||||
pub use self::{group::InputGroup, textarea::TextArea};
|
pub use self::{group::InputGroup, textarea::TextArea};
|
||||||
use crate::{prelude::*, render};
|
use crate::{prelude::*, render};
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
#[cfg(feature = "validate")]
|
||||||
|
use validator::ValidationErrors;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
|
@ -65,11 +67,7 @@ impl Component for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let input_type = self
|
let input_type = self.props.input_type.as_ref().unwrap_or(&InputType::Text);
|
||||||
.props
|
|
||||||
.input_type
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or_else(|| &InputType::Text);
|
|
||||||
let mut prefix = if self.props.readonly {
|
let mut prefix = if self.props.readonly {
|
||||||
vec!["form-control-plaintext"]
|
vec!["form-control-plaintext"]
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,3 +85,21 @@ impl Component for Input {
|
||||||
render::render_with_prefix(&self.props, prefix, html)
|
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 {
|
||||||
|
let errors = errors.field_errors();
|
||||||
|
if let Some(errors) = errors.get(field.as_ref()) {
|
||||||
|
html! {
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
{ for errors.iter().filter_map(|error| error.message.as_ref()) }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use super::props::Props;
|
use super::props::Props;
|
||||||
use crate::{prelude::*, render};
|
use crate::{prelude::*, render};
|
||||||
|
#[cfg(feature = "validate")]
|
||||||
|
use validator::ValidationErrors;
|
||||||
use yew::{prelude::*, virtual_dom::VNode};
|
use yew::{prelude::*, virtual_dom::VNode};
|
||||||
|
|
||||||
pub struct TextArea {
|
pub struct TextArea {
|
||||||
link: ComponentLink<Self>,
|
link: ComponentLink<Self>,
|
||||||
state: String,
|
state: String,
|
||||||
props: Props,
|
props: Props,
|
||||||
|
#[cfg(feature = "validator")]
|
||||||
|
errors: Option<ValidationErrors>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -15,11 +19,23 @@ impl Component for TextArea {
|
||||||
type Message = InputChange;
|
type Message = InputChange;
|
||||||
type Properties = Props;
|
type Properties = Props;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "validate"))]
|
||||||
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
fn create(props: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||||
let state = extract_state(&props);
|
let state = extract_state(&props);
|
||||||
Self { props, state, link }
|
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 {
|
fn update(&mut self, msg: Self::Message) -> ShouldRender {
|
||||||
if let InputChange(ChangeData::Value(value)) = msg {
|
if let InputChange(ChangeData::Value(value)) = msg {
|
||||||
self.state = value.clone();
|
self.state = value.clone();
|
||||||
|
@ -38,15 +54,42 @@ impl Component for TextArea {
|
||||||
should_render
|
should_render
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "validate"))]
|
||||||
fn view(&self) -> Html {
|
fn view(&self) -> Html {
|
||||||
let prefix = vec!["form-control", &valid_as_class(&self.props.valid)];
|
let prefix = vec!["form-control", &valid_as_class(&self.props.valid)];
|
||||||
let html = html! {
|
let html = {
|
||||||
|
html! {
|
||||||
<textarea
|
<textarea
|
||||||
readonly=self.props.readonly
|
readonly=self.props.readonly
|
||||||
onchange=self.link.callback(|evt| InputChange(evt))
|
onchange=self.link.callback(|evt| InputChange(evt))
|
||||||
>
|
>
|
||||||
{ &self.state }
|
{ &self.state }
|
||||||
</textarea>
|
</textarea>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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 }
|
||||||
|
<textarea
|
||||||
|
readonly=self.props.readonly
|
||||||
|
onchange=self.link.callback(|evt| InputChange(evt))
|
||||||
|
>
|
||||||
|
{ &self.state }
|
||||||
|
</textarea>
|
||||||
|
</>
|
||||||
|
}
|
||||||
};
|
};
|
||||||
render::render_with_prefix(&self.props, prefix, html)
|
render::render_with_prefix(&self.props, prefix, html)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue