generated from mitchell/rust_template
conditional validation
This commit is contained in:
parent
bbde4d6331
commit
89375a5b0c
@ -44,7 +44,7 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
let cx = self.cx.clone();
|
let cx = self.cx.clone();
|
||||||
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
|
let render_fn = move |fs: Rc<FD::Style>, fd: RwSignal<FD>| {
|
||||||
let render_data = Rc::new(render_data);
|
let render_data = Rc::new(render_data);
|
||||||
// let cloned_fs = fs.clone();
|
|
||||||
let view = move || fs.clone().button(render_data.clone(), fd);
|
let view = move || fs.clone().button(render_data.clone(), fd);
|
||||||
let view = match show_when {
|
let view = match show_when {
|
||||||
Some(when) => {
|
Some(when) => {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub mod text_area;
|
|||||||
pub mod text_input;
|
pub mod text_input;
|
||||||
|
|
||||||
pub trait BuilderFn<B, CX>: Fn(B, Rc<CX>) -> B {}
|
pub trait BuilderFn<B, CX>: Fn(B, Rc<CX>) -> B {}
|
||||||
pub trait ValidationFn<FDT: ?Sized>: Fn(&FDT) -> Result<(), String> + 'static {}
|
pub trait ValidationFn<FD: ?Sized>: Fn(&FD) -> 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 {}
|
||||||
@ -177,7 +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>>>,
|
pub(crate) show_when: Option<Rc<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder for a interactive control.
|
/// A builder for a interactive control.
|
||||||
@ -188,7 +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(crate) show_when: Option<Rc<dyn ShowWhenFn<FD, FD::Context>>>,
|
||||||
pub data: C,
|
pub data: C,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ impl<FD: FormToolData, C: ControlData, FDT> ControlBuilder<FD, C, FDT> {
|
|||||||
mut self,
|
mut self,
|
||||||
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
when: impl Fn(Signal<FD>, Rc<FD::Context>) -> bool + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.show_when = Some(Box::new(when));
|
self.show_when = Some(Rc::new(when));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,9 @@ impl<FD: FormToolData> FormValidator<FD> {
|
|||||||
/// With this, you can render the form, get the form data, or get
|
/// With this, you can render the form, get the form data, or get
|
||||||
/// a validator for the data.
|
/// a validator for the data.
|
||||||
pub struct Form<FD: FormToolData> {
|
pub struct Form<FD: FormToolData> {
|
||||||
|
/// The form data signal.
|
||||||
pub fd: RwSignal<FD>,
|
pub fd: RwSignal<FD>,
|
||||||
|
/// The list of validations
|
||||||
pub(crate) validations: Vec<Rc<dyn ValidationFn<FD>>>,
|
pub(crate) validations: Vec<Rc<dyn ValidationFn<FD>>>,
|
||||||
pub(crate) view: View,
|
pub(crate) view: View,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,8 +125,24 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
Err(e) => panic!("Invalid Component: {}", e),
|
Err(e) => panic!("Invalid Component: {}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref validation_fn) = built_control_data.validation_fn {
|
if let Some(validation_fn) = built_control_data.validation_fn.clone() {
|
||||||
self.validations.push(validation_fn.clone());
|
let validation_fn = if let Some(show_when) = built_control_data.show_when.clone() {
|
||||||
|
// we want the validation function to always succeed for hidden components
|
||||||
|
// thus, we need to modify the validation function
|
||||||
|
let cx = self.cx.clone();
|
||||||
|
let new_validation_fn = move |fd: &FD| {
|
||||||
|
let (fd_signal, _) = create_signal(fd.clone());
|
||||||
|
if !show_when(fd_signal.into(), cx.clone()) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
validation_fn(fd)
|
||||||
|
};
|
||||||
|
Rc::new(new_validation_fn)
|
||||||
|
} else {
|
||||||
|
validation_fn
|
||||||
|
};
|
||||||
|
|
||||||
|
self.validations.push(validation_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cx = self.cx.clone();
|
let cx = self.cx.clone();
|
||||||
@ -174,14 +190,29 @@ impl<FD: FormToolData> FormBuilder<FD> {
|
|||||||
};
|
};
|
||||||
let value_getter = value_getter.into_signal();
|
let value_getter = value_getter.into_signal();
|
||||||
|
|
||||||
|
let cloned_show_when = show_when.clone();
|
||||||
|
let cloned_cx = cx.clone();
|
||||||
let validation_cb = move || {
|
let validation_cb = move || {
|
||||||
let validation_fn = validation_fn.as_ref();
|
// first check if the validation signal is an error so that we
|
||||||
|
// can fail on parsing issues too
|
||||||
|
if let Some(Err(_)) = validation_signal.try_get_untracked() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation for non-visible fields always succeeds
|
||||||
|
if let Some(ref show_when) = cloned_show_when {
|
||||||
|
if !show_when(fd.into(), cloned_cx.clone()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the validation function on the value now
|
||||||
let validation_fn = match validation_fn {
|
let validation_fn = match validation_fn {
|
||||||
Some(v) => v,
|
Some(ref v) => v,
|
||||||
None => return true, // No validation function, so validation passes
|
None => return true, // No validation function so validation passes
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = fd.get();
|
let data = fd.get_untracked();
|
||||||
let validation_result = validation_fn(&data);
|
let validation_result = validation_fn(&data);
|
||||||
let succeeded = validation_result.is_ok();
|
let succeeded = validation_result.is_ok();
|
||||||
validation_signal_set.set(validation_result);
|
validation_signal_set.set(validation_result);
|
||||||
|
|||||||
Reference in New Issue
Block a user