mirror of
https://github.com/adoyle0/thaw.git
synced 2025-02-02 08:34:15 -05:00
refactor: Rule::validate
This commit is contained in:
parent
a50f8ff3bf
commit
3ac0a6cd85
4 changed files with 73 additions and 101 deletions
|
@ -1,4 +1,4 @@
|
||||||
use crate::{FieldInjection, FieldValidationState, Rule, RuleValueIsEmpty};
|
use crate::{FieldInjection, FieldValidationState, Rule};
|
||||||
use leptos::{context::Provider, prelude::*};
|
use leptos::{context::Provider, prelude::*};
|
||||||
use std::{collections::HashSet, ops::Deref};
|
use std::{collections::HashSet, ops::Deref};
|
||||||
use thaw_utils::{class_list, Model};
|
use thaw_utils::{class_list, Model};
|
||||||
|
@ -63,26 +63,43 @@ pub struct CheckboxGroupRule(Rule<HashSet<String>, CheckboxGroupRuleTrigger>);
|
||||||
|
|
||||||
impl CheckboxGroupRule {
|
impl CheckboxGroupRule {
|
||||||
pub fn required(required: MaybeSignal<bool>) -> Self {
|
pub fn required(required: MaybeSignal<bool>) -> Self {
|
||||||
Self(Rule::required(required))
|
Self::validator(move |value, name| {
|
||||||
|
if required.get_untracked() && value.is_empty() {
|
||||||
|
let message = name.get_untracked().map_or_else(
|
||||||
|
|| String::from("Please select!"),
|
||||||
|
|name| format!("Please select {name}!"),
|
||||||
|
);
|
||||||
|
Err(FieldValidationState::Error(message))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn required_with_message(
|
pub fn required_with_message(
|
||||||
required: MaybeSignal<bool>,
|
required: MaybeSignal<bool>,
|
||||||
message: MaybeSignal<String>,
|
message: MaybeSignal<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Rule::required_with_message(required, message))
|
Self::validator(move |value, _| {
|
||||||
|
if required.get_untracked() && value.is_empty() {
|
||||||
|
Err(FieldValidationState::Error(message.get_untracked()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validator(
|
pub fn validator(
|
||||||
f: impl Fn(&HashSet<String>) -> Result<(), FieldValidationState> + Send + Sync + 'static,
|
f: impl Fn(&HashSet<String>, Signal<Option<String>>) -> Result<(), FieldValidationState>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Rule::validator(f))
|
Self(Rule::validator(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_trigger(mut self, trigger: CheckboxGroupRuleTrigger) -> Self {
|
pub fn with_trigger(self, trigger: CheckboxGroupRuleTrigger) -> Self {
|
||||||
self.0.trigger = trigger;
|
Self(Rule::with_trigger(self.0, trigger))
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,9 +110,3 @@ impl Deref for CheckboxGroupRule {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RuleValueIsEmpty for HashSet<String> {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,86 +3,40 @@ use leptos::prelude::*;
|
||||||
use send_wrapper::SendWrapper;
|
use send_wrapper::SendWrapper;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
enum RuleValidator<T> {
|
type RuleValidator<T> = Box<dyn Fn(&T, Signal<Option<String>>) -> Result<(), FieldValidationState>>;
|
||||||
Required(MaybeSignal<bool>),
|
|
||||||
RequiredMessage(MaybeSignal<bool>, MaybeSignal<String>),
|
|
||||||
Validator(Box<dyn Fn(&T) -> Result<(), FieldValidationState>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule<T, Trigger> {
|
pub struct Rule<T, Trigger> {
|
||||||
validator: RuleValidator<T>,
|
validator: RuleValidator<T>,
|
||||||
pub trigger: Trigger,
|
trigger: Trigger,
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, Trigger> Rule<T, Trigger>
|
|
||||||
where
|
|
||||||
Trigger: Default,
|
|
||||||
{
|
|
||||||
pub fn required(required: MaybeSignal<bool>) -> Self {
|
|
||||||
Self {
|
|
||||||
trigger: Default::default(),
|
|
||||||
validator: RuleValidator::Required(required),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn required_with_message(
|
|
||||||
required: MaybeSignal<bool>,
|
|
||||||
message: MaybeSignal<String>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
trigger: Default::default(),
|
|
||||||
validator: RuleValidator::RequiredMessage(required, message),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validator(
|
|
||||||
f: impl Fn(&T) -> Result<(), FieldValidationState> + Send + Sync + 'static,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
trigger: Default::default(),
|
|
||||||
validator: RuleValidator::Validator(Box::new(f)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Trigger> Rule<T, Trigger> {
|
impl<T, Trigger> Rule<T, Trigger> {
|
||||||
|
pub fn validator(
|
||||||
|
f: impl Fn(&T, Signal<Option<String>>) -> Result<(), FieldValidationState>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Trigger: Default,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
trigger: Default::default(),
|
||||||
|
validator: Box::new(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_trigger(mut self, trigger: Trigger) -> Self {
|
pub fn with_trigger(mut self, trigger: Trigger) -> Self {
|
||||||
self.trigger = trigger;
|
self.trigger = trigger;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
|
pub fn validate<V, R>(
|
||||||
pub fn call_validator<V: WithUntracked<Value = T>>(
|
rules: Vec<R>,
|
||||||
&self,
|
|
||||||
value: V,
|
value: V,
|
||||||
name: Signal<Option<String>>,
|
name: Signal<Option<String>>,
|
||||||
) -> Result<(), FieldValidationState> {
|
) -> Callback<Option<Trigger>, bool>
|
||||||
value.with_untracked(|value| match &self.validator {
|
|
||||||
RuleValidator::Required(required) => {
|
|
||||||
if required.get_untracked() && RuleValueIsEmpty::is_empty(value) {
|
|
||||||
let message = name.get_untracked().map_or_else(
|
|
||||||
|| String::from("Please input!"),
|
|
||||||
|name| format!("Please input {name}!"),
|
|
||||||
);
|
|
||||||
Err(FieldValidationState::Error(message))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RuleValidator::RequiredMessage(required, message) => {
|
|
||||||
if required.get_untracked() && RuleValueIsEmpty::is_empty(value) {
|
|
||||||
Err(FieldValidationState::Error(message.get_untracked()))
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RuleValidator::Validator(f) => f(value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate<V, R>(rules: Vec<R>, value: V, name: Signal<Option<String>>) -> Callback<Option<Trigger>, bool>
|
|
||||||
where
|
where
|
||||||
V: WithUntracked<Value = T>,
|
V: WithUntracked<Value = T>,
|
||||||
V: Send + Sync + Copy + 'static,
|
V: Send + Sync + Copy + 'static,
|
||||||
|
@ -115,7 +69,7 @@ impl<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
|
||||||
}
|
}
|
||||||
call_count += 1;
|
call_count += 1;
|
||||||
|
|
||||||
let state = rule.call_validator(value, name);
|
let state = value.with_untracked(|value| (rule.validator)(value, name));
|
||||||
if state.is_err() {
|
if state.is_err() {
|
||||||
return Some(state);
|
return Some(state);
|
||||||
}
|
}
|
||||||
|
@ -139,13 +93,3 @@ impl<T: RuleValueIsEmpty, Trigger> Rule<T, Trigger> {
|
||||||
validate
|
validate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RuleValueIsEmpty {
|
|
||||||
fn is_empty(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RuleValueIsEmpty for String {
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::Deref;
|
|
||||||
use crate::{FieldInjection, FieldValidationState, Rule};
|
use crate::{FieldInjection, FieldValidationState, Rule};
|
||||||
use leptos::{ev, html, prelude::*};
|
use leptos::{ev, html, prelude::*};
|
||||||
|
use std::ops::Deref;
|
||||||
use thaw_utils::{
|
use thaw_utils::{
|
||||||
class_list, mount_style, ArcOneCallback, BoxOneCallback, ComponentRef, Model, OptionalProp,
|
class_list, mount_style, ArcOneCallback, BoxOneCallback, ComponentRef, Model, OptionalProp,
|
||||||
};
|
};
|
||||||
|
@ -266,26 +266,43 @@ pub struct InputRule(Rule<String, InputRuleTrigger>);
|
||||||
|
|
||||||
impl InputRule {
|
impl InputRule {
|
||||||
pub fn required(required: MaybeSignal<bool>) -> Self {
|
pub fn required(required: MaybeSignal<bool>) -> Self {
|
||||||
Self(Rule::required(required))
|
Self::validator(move |value, name| {
|
||||||
|
if required.get_untracked() && value.is_empty() {
|
||||||
|
let message = name.get_untracked().map_or_else(
|
||||||
|
|| String::from("Please input!"),
|
||||||
|
|name| format!("Please input {name}!"),
|
||||||
|
);
|
||||||
|
Err(FieldValidationState::Error(message))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn required_with_message(
|
pub fn required_with_message(
|
||||||
required: MaybeSignal<bool>,
|
required: MaybeSignal<bool>,
|
||||||
message: MaybeSignal<String>,
|
message: MaybeSignal<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Rule::required_with_message(required,message))
|
Self::validator(move |value, _| {
|
||||||
|
if required.get_untracked() && value.is_empty() {
|
||||||
|
Err(FieldValidationState::Error(message.get_untracked()))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validator(
|
pub fn validator(
|
||||||
f: impl Fn(&String) -> Result<(), FieldValidationState> + Send + Sync + 'static,
|
f: impl Fn(&String, Signal<Option<String>>) -> Result<(), FieldValidationState>
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(Rule::validator(f))
|
Self(Rule::validator(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_trigger(mut self, trigger: InputRuleTrigger) -> Self {
|
pub fn with_trigger(self, trigger: InputRuleTrigger) -> Self {
|
||||||
self.0.trigger = trigger;
|
Self(Rule::with_trigger(self.0, trigger))
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue