generated from mitchell/rust_template
control flow
This commit is contained in:
parent
0339a2ee96
commit
835271cd22
@ -1,29 +1,37 @@
|
|||||||
use super::{BuilderFn, ControlBuilder, ControlData, ControlRenderData};
|
use super::{
|
||||||
|
BuilderFn, ControlRenderData, GetterVanityControlData, VanityControlBuilder, VanityControlData,
|
||||||
|
};
|
||||||
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
use crate::{form::FormToolData, form_builder::FormBuilder, styles::FormStyle};
|
||||||
use leptos::{Signal, View};
|
use leptos::{Signal, View};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct HiddenData;
|
pub struct HiddenData {
|
||||||
|
pub name: String,
|
||||||
impl ControlData for HiddenData {
|
}
|
||||||
type ReturnType = String;
|
|
||||||
|
|
||||||
|
impl VanityControlData for HiddenData {
|
||||||
fn build_control<FS: FormStyle>(
|
fn build_control<FS: FormStyle>(
|
||||||
fs: &FS,
|
fs: &FS,
|
||||||
control: ControlRenderData<FS, Self>,
|
control: ControlRenderData<FS, Self>,
|
||||||
value_getter: Signal<Self::ReturnType>,
|
value_getter: Option<Signal<String>>,
|
||||||
_value_setter: Box<dyn Fn(Self::ReturnType)>,
|
|
||||||
_validation_state: Signal<Result<(), String>>,
|
|
||||||
) -> View {
|
) -> View {
|
||||||
fs.hidden(control, value_getter)
|
fs.hidden(control, value_getter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl GetterVanityControlData for HiddenData {}
|
||||||
|
|
||||||
impl<FD: FormToolData> FormBuilder<FD> {
|
impl<FD: FormToolData> FormBuilder<FD> {
|
||||||
pub fn hidden<FDT: Clone + PartialEq + 'static>(
|
pub fn hidden(
|
||||||
self,
|
self,
|
||||||
builder: impl BuilderFn<ControlBuilder<FD, HiddenData, FDT>, FD::Context>,
|
builder: impl BuilderFn<VanityControlBuilder<FD, HiddenData>, FD::Context>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.new_control(builder)
|
self.new_vanity(builder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<FD: FormToolData> VanityControlBuilder<FD, HiddenData> {
|
||||||
|
pub fn named(mut self, control_name: impl ToString) -> Self {
|
||||||
|
self.data.name = control_name.to_string();
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,13 @@ pub mod text_area;
|
|||||||
pub mod text_input;
|
pub mod text_input;
|
||||||
|
|
||||||
pub trait BuilderFn<B, CX>: Fn(B, &CX) -> B {}
|
pub trait BuilderFn<B, CX>: Fn(B, &CX) -> B {}
|
||||||
pub trait ValidationFn<FDT>: Fn(&FDT) -> Result<(), String> + 'static {}
|
pub trait ValidationFn<FDT: ?Sized>: Fn(&FDT) -> Result<(), String> + 'static {}
|
||||||
pub trait ValidationCb: Fn() -> bool + 'static {}
|
pub trait ValidationCb: Fn() -> bool + 'static {}
|
||||||
pub trait ParseFn<CR, FDT>: Fn(CR) -> Result<FDT, String> + 'static {}
|
pub trait ParseFn<CR, FDT>: Fn(CR) -> Result<FDT, String> + 'static {}
|
||||||
pub trait UnparseFn<CR, FDT>: Fn(FDT) -> CR + 'static {}
|
pub trait UnparseFn<CR, FDT>: Fn(FDT) -> CR + 'static {}
|
||||||
pub trait FieldGetter<FD, FDT>: Fn(FD) -> FDT + 'static {}
|
pub trait FieldGetter<FD, FDT>: Fn(FD) -> FDT + 'static {}
|
||||||
pub trait FieldSetter<FD, FDT>: Fn(&mut FD, FDT) + 'static {}
|
pub trait FieldSetter<FD, FDT>: Fn(&mut FD, FDT) + 'static {}
|
||||||
|
pub trait ShowWhenFn<FD: 'static, CX>: Fn(Signal<FD>, Rc<CX>) -> bool + 'static {}
|
||||||
pub trait RenderFn<FS, FD>:
|
pub trait RenderFn<FS, FD>:
|
||||||
FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
|
FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
|
||||||
{
|
{
|
||||||
@ -38,6 +39,7 @@ impl<CR, FDT, F> ParseFn<CR, FDT> for F where F: Fn(CR) -> Result<FDT, String> +
|
|||||||
impl<CR, FDT, F> UnparseFn<CR, FDT> for F where F: Fn(FDT) -> CR + 'static {}
|
impl<CR, FDT, F> UnparseFn<CR, FDT> for F where F: Fn(FDT) -> CR + 'static {}
|
||||||
impl<FD, FDT, F> FieldGetter<FD, FDT> for F where F: Fn(FD) -> FDT + 'static {}
|
impl<FD, FDT, F> FieldGetter<FD, FDT> for F where F: Fn(FD) -> FDT + 'static {}
|
||||||
impl<FD, FDT, F> FieldSetter<FD, FDT> for F where F: Fn(&mut FD, FDT) + 'static {}
|
impl<FD, FDT, F> FieldSetter<FD, FDT> for F where F: Fn(&mut FD, FDT) + 'static {}
|
||||||
|
impl<FD: 'static, CX, F> ShowWhenFn<FD, CX> for F where F: Fn(Signal<FD>, Rc<CX>) -> bool + 'static {}
|
||||||
impl<FS, FD, F> RenderFn<FS, FD> for F where
|
impl<FS, FD, F> RenderFn<FS, FD> for F where
|
||||||
F: FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
|
F: FnOnce(&FS, RwSignal<FD>) -> (View, Option<Box<dyn ValidationCb>>) + 'static
|
||||||
{
|
{
|
||||||
@ -81,11 +83,13 @@ pub struct VanityControlBuilder<FD: FormToolData, C: VanityControlData> {
|
|||||||
pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
|
pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
|
||||||
pub(crate) data: C,
|
pub(crate) data: C,
|
||||||
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
||||||
|
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct BuiltVanityControlData<FD: FormToolData, C: VanityControlData> {
|
pub(crate) struct BuiltVanityControlData<FD: FormToolData, C: VanityControlData> {
|
||||||
pub(crate) render_data: ControlRenderData<FD::Style, C>,
|
pub(crate) render_data: ControlRenderData<FD::Style, C>,
|
||||||
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
pub(crate) getter: Option<Rc<dyn FieldGetter<FD, String>>>,
|
||||||
|
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, C: VanityControlData> VanityControlBuilder<FD, C> {
|
impl<FD: FormToolData, C: VanityControlData> VanityControlBuilder<FD, C> {
|
||||||
@ -95,6 +99,7 @@ impl<FD: FormToolData, C: VanityControlData> VanityControlBuilder<FD, C> {
|
|||||||
data,
|
data,
|
||||||
style_attributes: Vec::new(),
|
style_attributes: Vec::new(),
|
||||||
getter: None,
|
getter: None,
|
||||||
|
show_when: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,9 +111,21 @@ impl<FD: FormToolData, C: VanityControlData> VanityControlBuilder<FD, C> {
|
|||||||
styles: self.style_attributes,
|
styles: self.style_attributes,
|
||||||
},
|
},
|
||||||
getter: self.getter,
|
getter: self.getter,
|
||||||
|
show_when: self.show_when,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the function to decide when to render the control.
|
||||||
|
///
|
||||||
|
/// Validations for components that are not shown DO NOT run.
|
||||||
|
pub fn show_when(
|
||||||
|
mut self,
|
||||||
|
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
||||||
|
) -> Self {
|
||||||
|
self.show_when = Some(Box::new(when));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a styling attribute to this control.
|
/// Adds a styling attribute to this control.
|
||||||
pub fn style(mut self, attribute: <FD::Style as FormStyle>::StylingAttributes) -> Self {
|
pub fn style(mut self, attribute: <FD::Style as FormStyle>::StylingAttributes) -> Self {
|
||||||
self.style_attributes.push(attribute);
|
self.style_attributes.push(attribute);
|
||||||
@ -160,6 +177,7 @@ pub(crate) struct BuiltControlData<FD: FormToolData, C: ControlData, FDT> {
|
|||||||
pub(crate) parse_fn: Box<dyn ParseFn<C::ReturnType, FDT>>,
|
pub(crate) parse_fn: Box<dyn ParseFn<C::ReturnType, FDT>>,
|
||||||
pub(crate) unparse_fn: Box<dyn UnparseFn<C::ReturnType, FDT>>,
|
pub(crate) unparse_fn: Box<dyn UnparseFn<C::ReturnType, FDT>>,
|
||||||
pub(crate) validation_fn: Option<Rc<dyn ValidationFn<FD>>>,
|
pub(crate) validation_fn: Option<Rc<dyn ValidationFn<FD>>>,
|
||||||
|
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder for a interactive control.
|
/// A builder for a interactive control.
|
||||||
@ -170,6 +188,7 @@ pub struct ControlBuilder<FD: FormToolData, C: ControlData, FDT> {
|
|||||||
pub(crate) unparse_fn: Option<Box<dyn UnparseFn<C::ReturnType, FDT>>>,
|
pub(crate) unparse_fn: Option<Box<dyn UnparseFn<C::ReturnType, FDT>>>,
|
||||||
pub(crate) validation_fn: Option<Rc<dyn ValidationFn<FD>>>,
|
pub(crate) validation_fn: Option<Rc<dyn ValidationFn<FD>>>,
|
||||||
pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
|
pub(crate) style_attributes: Vec<<FD::Style as FormStyle>::StylingAttributes>,
|
||||||
|
pub(crate) show_when: Option<Box<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
pub data: C,
|
pub data: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +203,7 @@ impl<FD: FormToolData, C: ControlData, FDT> ControlBuilder<FD, C, FDT> {
|
|||||||
unparse_fn: None,
|
unparse_fn: None,
|
||||||
validation_fn: None,
|
validation_fn: None,
|
||||||
style_attributes: Vec::new(),
|
style_attributes: Vec::new(),
|
||||||
|
show_when: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,9 +238,21 @@ impl<FD: FormToolData, C: ControlData, FDT> ControlBuilder<FD, C, FDT> {
|
|||||||
parse_fn,
|
parse_fn,
|
||||||
unparse_fn,
|
unparse_fn,
|
||||||
validation_fn: self.validation_fn,
|
validation_fn: self.validation_fn,
|
||||||
|
show_when: self.show_when,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the function to decide when to render the control.
|
||||||
|
///
|
||||||
|
/// Validations for components that are not shown DO NOT run.
|
||||||
|
pub fn show_when(
|
||||||
|
mut self,
|
||||||
|
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
||||||
|
) -> Self {
|
||||||
|
self.show_when = Some(Box::new(when));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the getter function.
|
/// Sets the getter function.
|
||||||
///
|
///
|
||||||
/// This function should get the field from the form data
|
/// This function should get the field from the form data
|
||||||
@ -243,7 +275,7 @@ impl<FD: FormToolData, C: ControlData, FDT> ControlBuilder<FD, C, FDT> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the parse functions to the ones given
|
/// Sets the parse functions to the ones given.
|
||||||
///
|
///
|
||||||
/// The parse and unparse functions define how to turn what the user
|
/// The parse and unparse functions define how to turn what the user
|
||||||
/// types in the form into what is stored in the form data struct and
|
/// types in the form into what is stored in the form data struct and
|
||||||
|
|||||||
@ -16,9 +16,6 @@ use serde::de::DeserializeOwned;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use web_sys::{FormData, SubmitEvent};
|
use web_sys::{FormData, SubmitEvent};
|
||||||
|
|
||||||
// TODO: FS, and CX may be uncessisary, as FS is the same as FD::Style
|
|
||||||
// and CX is the same as FD::Context.
|
|
||||||
|
|
||||||
/// A builder for laying out forms.
|
/// A builder for laying out forms.
|
||||||
///
|
///
|
||||||
/// This builder allows you to specify what components should make up the form.
|
/// This builder allows you to specify what components should make up the form.
|
||||||
@ -92,11 +89,24 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
let BuiltVanityControlData {
|
let BuiltVanityControlData {
|
||||||
render_data,
|
render_data,
|
||||||
getter,
|
getter,
|
||||||
|
show_when,
|
||||||
} = vanity_control.build();
|
} = vanity_control.build();
|
||||||
|
|
||||||
|
let cx = self.cx.clone();
|
||||||
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
|
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
|
||||||
let value_getter = getter.map(|getter| (move || getter(fd.get())).into_signal());
|
let value_getter = getter.map(|getter| (move || getter(fd.get())).into_signal());
|
||||||
let view = VanityControlData::build_control(fs, render_data, value_getter);
|
let view = VanityControlData::build_control(fs, render_data, value_getter);
|
||||||
|
let view = match show_when {
|
||||||
|
Some(when) => {
|
||||||
|
let when = move || when(fd.into(), cx.clone());
|
||||||
|
view! {
|
||||||
|
<Show when=when>
|
||||||
|
{&view}
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => view,
|
||||||
|
};
|
||||||
(view, None)
|
(view, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,8 +127,9 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
self.validations.push(validation_fn.clone());
|
self.validations.push(validation_fn.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cx = self.cx.clone();
|
||||||
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
|
let render_fn = move |fs: &FD::Style, fd: RwSignal<FD>| {
|
||||||
let (view, cb) = Self::build_control_view(fd, fs, built_control_data);
|
let (view, cb) = Self::build_control_view(fd, fs, built_control_data, cx);
|
||||||
(view, Some(cb))
|
(view, Some(cb))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,6 +140,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
fd: RwSignal<FD>,
|
fd: RwSignal<FD>,
|
||||||
fs: &FD::Style,
|
fs: &FD::Style,
|
||||||
control_data: BuiltControlData<FD, C, FDT>,
|
control_data: BuiltControlData<FD, C, FDT>,
|
||||||
|
cx: Rc<FD::Context>,
|
||||||
) -> (View, Box<dyn ValidationCb>) {
|
) -> (View, Box<dyn ValidationCb>) {
|
||||||
let BuiltControlData {
|
let BuiltControlData {
|
||||||
render_data,
|
render_data,
|
||||||
@ -137,6 +149,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
parse_fn,
|
parse_fn,
|
||||||
unparse_fn,
|
unparse_fn,
|
||||||
validation_fn,
|
validation_fn,
|
||||||
|
show_when,
|
||||||
} = control_data;
|
} = control_data;
|
||||||
|
|
||||||
let (validation_signal, validation_signal_set) = create_signal(Ok(()));
|
let (validation_signal, validation_signal_set) = create_signal(Ok(()));
|
||||||
@ -188,6 +201,17 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
value_setter,
|
value_setter,
|
||||||
validation_signal.into(),
|
validation_signal.into(),
|
||||||
);
|
);
|
||||||
|
let view = match show_when {
|
||||||
|
Some(when) => {
|
||||||
|
let when = move || when(fd.into(), cx.clone());
|
||||||
|
view! {
|
||||||
|
<Show when=when>
|
||||||
|
{&view}
|
||||||
|
</Show>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => view,
|
||||||
|
};
|
||||||
(view, validation_cb)
|
(view, validation_cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -77,6 +77,13 @@ impl FormStyle for GridFormStyle {
|
|||||||
value_setter: Box<dyn Fn(<SelectData as ControlData>::ReturnType)>,
|
value_setter: Box<dyn Fn(<SelectData as ControlData>::ReturnType)>,
|
||||||
validation_state: Signal<Result<(), String>>,
|
validation_state: Signal<Result<(), String>>,
|
||||||
) -> View {
|
) -> View {
|
||||||
|
let mut width = 1;
|
||||||
|
for style in control.styles {
|
||||||
|
match style {
|
||||||
|
GridFormStylingAttributes::Width(w) => width = w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let options_view = control
|
let options_view = control
|
||||||
.data
|
.data
|
||||||
.options
|
.options
|
||||||
@ -91,9 +98,13 @@ impl FormStyle for GridFormStyle {
|
|||||||
.collect_view();
|
.collect_view();
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div style:grid-column=format!("span {}", width)>
|
||||||
<span>{control.data.label}</span>
|
<div>
|
||||||
{move || validation_state.get().err()}
|
<label for=&control.data.name class="form_label">
|
||||||
|
{control.data.label.as_ref()}
|
||||||
|
</label>
|
||||||
|
<span class="form_error">{move || validation_state.get().err()}</span>
|
||||||
|
</div>
|
||||||
<select
|
<select
|
||||||
id=&control.data.name
|
id=&control.data.name
|
||||||
name=control.data.name
|
name=control.data.name
|
||||||
@ -147,10 +158,12 @@ impl FormStyle for GridFormStyle {
|
|||||||
|
|
||||||
fn hidden(
|
fn hidden(
|
||||||
&self,
|
&self,
|
||||||
_control: ControlRenderData<Self, HiddenData>,
|
control: ControlRenderData<Self, HiddenData>,
|
||||||
value_getter: Signal<String>,
|
value_getter: Option<Signal<String>>,
|
||||||
) -> View {
|
) -> View {
|
||||||
view! { <input prop:value=value_getter style="visibility: hidden"/> }.into_view()
|
let value_getter = move || value_getter.map(|g| g.get());
|
||||||
|
view! { <input name=control.data.name prop:value=value_getter style="visibility: hidden"/> }
|
||||||
|
.into_view()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn radio_buttons(
|
fn radio_buttons(
|
||||||
|
|||||||
@ -28,7 +28,7 @@ pub trait FormStyle: 'static {
|
|||||||
fn hidden(
|
fn hidden(
|
||||||
&self,
|
&self,
|
||||||
control: ControlRenderData<Self, HiddenData>,
|
control: ControlRenderData<Self, HiddenData>,
|
||||||
value_getter: Signal<String>,
|
value_getter: Option<Signal<String>>,
|
||||||
) -> View;
|
) -> View;
|
||||||
fn text_input(
|
fn text_input(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ type ValidationBuilderFn<T> = dyn Fn(&str, &T) -> Result<(), String> + 'static;
|
|||||||
/// closures, but for simple validation function this builder can be helpful
|
/// closures, but for simple validation function this builder can be helpful
|
||||||
///
|
///
|
||||||
/// Validations are run in the order that they are called in the builder.
|
/// Validations are run in the order that they are called in the builder.
|
||||||
pub struct ValidationBuilder<FD: FormToolData, T: 'static> {
|
pub struct ValidationBuilder<FD: FormToolData, T: ?Sized + 'static> {
|
||||||
/// The name of the field, for error messages.
|
/// The name of the field, for error messages.
|
||||||
name: String,
|
name: String,
|
||||||
/// The getter function for the field to validate.
|
/// The getter function for the field to validate.
|
||||||
@ -23,7 +23,7 @@ pub struct ValidationBuilder<FD: FormToolData, T: 'static> {
|
|||||||
functions: Vec<Box<ValidationBuilderFn<T>>>,
|
functions: Vec<Box<ValidationBuilderFn<T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, T: 'static> ValidationBuilder<FD, T> {
|
impl<FD: FormToolData, T: ?Sized + 'static> ValidationBuilder<FD, T> {
|
||||||
/// Creates a new empty [`ValidationBuilder`] on the given field.
|
/// Creates a new empty [`ValidationBuilder`] on the given field.
|
||||||
pub fn for_field(field_fn: impl Fn(&FD) -> &T + 'static) -> Self {
|
pub fn for_field(field_fn: impl Fn(&FD) -> &T + 'static) -> Self {
|
||||||
ValidationBuilder {
|
ValidationBuilder {
|
||||||
@ -65,7 +65,7 @@ impl<FD: FormToolData, T: 'static> ValidationBuilder<FD, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData> ValidationBuilder<FD, String> {
|
impl<FD: FormToolData> ValidationBuilder<FD, str> {
|
||||||
/// Requires the field to not be empty.
|
/// Requires the field to not be empty.
|
||||||
pub fn required(mut self) -> Self {
|
pub fn required(mut self) -> Self {
|
||||||
self.functions.push(Box::new(move |name, value| {
|
self.functions.push(Box::new(move |name, value| {
|
||||||
@ -101,6 +101,19 @@ impl<FD: FormToolData> ValidationBuilder<FD, String> {
|
|||||||
}));
|
}));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requires the field to contain `pattern`.
|
||||||
|
pub fn contains(mut self, pattern: impl ToString) -> Self {
|
||||||
|
let pattern = pattern.to_string();
|
||||||
|
self.functions.push(Box::new(move |name, value| {
|
||||||
|
if !value.contains(&pattern) {
|
||||||
|
Err(format!("{} must contain {}", name, &pattern))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FD: FormToolData, T: PartialOrd<T> + Display + 'static> ValidationBuilder<FD, T> {
|
impl<FD: FormToolData, T: PartialOrd<T> + Display + 'static> ValidationBuilder<FD, T> {
|
||||||
|
|||||||
Reference in New Issue
Block a user