impl ManagedField for BooleanField {
type Properties = Boolean;
type Message = Msg;
+ type ValidateClosure = ();
- fn validation_fn_need_update(_props: &Self::Properties, _old_props: &Self::Properties) -> bool {
- false
- }
+ fn validation_args(_props: &Self::Properties) -> Self::ValidateClosure { () }
fn setup(props: &Boolean) -> ManagedFieldState {
let mut value = false;
impl ManagedField for CheckboxField {
type Message = Msg;
type Properties = Checkbox;
+ type ValidateClosure = ();
- fn validation_fn_need_update(_props: &Self::Properties, _old_props: &Self::Properties) -> bool {
- false
- }
+ fn validation_args(_props: &Self::Properties) -> Self::ValidateClosure { () }
fn setup(props: &Checkbox) -> ManagedFieldState {
let on_value = props.value.as_deref().unwrap_or("on").to_string();
}
}
+#[derive(PartialEq)]
+pub struct ValidateClosure {
+ required: bool,
+ input_type: AttrValue,
+ min: Option<f64>,
+ max: Option<f64>,
+ validate: Option<ValidateFn<String>>,
+}
+
impl ManagedField for StandardField {
type Properties = Field;
type Message = Msg;
-
- fn validation_fn_need_update(props: &Self::Properties, old_props: &Self::Properties) -> bool {
- props.input_props.required != old_props.input_props.required
- || props.input_type != old_props.input_type
- || props.min != old_props.min
- || props.max != old_props.max
- || props.validate != old_props.validate
+ type ValidateClosure = ValidateClosure;
+
+ fn validation_args(props: &Self::Properties) -> Self::ValidateClosure {
+ ValidateClosure {
+ required: props.input_props.required,
+ input_type: props.input_type.clone(),
+ min: props.min,
+ max: props.max,
+ validate: props.validate.clone(),
+ }
}
- fn create_validation_fn(props: &Field) -> ValidateFn<Value> {
- let props = props.clone();
+ fn create_validation_fn(props: Self::ValidateClosure) -> ValidateFn<Value> {
ValidateFn::new(move |value: &Value| {
let value = match value {
Value::Null => String::new(),
};
if value.is_empty() {
- if props.input_props.required {
+ if props.required {
return Err(Error::msg(tr!("Field may not be empty.")));
} else {
return Ok(());
pub trait ManagedField: Sized {
type Properties: Properties + FieldBuilder;
type Message: 'static;
+ type ValidateClosure: 'static + PartialEq;
- fn validation_fn_need_update(props: &Self::Properties, old_props: &Self::Properties) -> bool {
- props != old_props
- }
+ /// Extract arguments passed to the [create_validation_fn](Self::create_validation_fn)
+ ///
+ /// This is called when component properties changes. We rebuild the
+ /// validation function if returend value changes.
+ fn validation_args(props: &Self::Properties) -> Self::ValidateClosure;
- fn create_validation_fn(_props: &Self::Properties) -> ValidateFn<Value> {
+ /// Create the validation function.
+ fn create_validation_fn(_props: Self::ValidateClosure) -> ValidateFn<Value> {
crate::static_validation_fn!(Value, |_| Ok(()))
}
fn create(ctx: &Context<Self>) -> Self {
let props = ctx.props();
- let validate = MF::create_validation_fn(props);
+ let validation_args = MF::validation_args(props);
+ let validate = MF::create_validation_fn(validation_args);
let mut comp_state = MF::setup(props);
comp_state.valid = validate
refresh1 = true;
}
- if MF::validation_fn_need_update(props, old_props) {
+ let old_validation_args = MF::validation_args(old_props);
+ let validation_args = MF::validation_args(props);
+
+ if validation_args != old_validation_args {
log::info!("UPDATE VF {:?}", input_props.name);
- let validate = MF::create_validation_fn(props);
+ let validate = MF::create_validation_fn(validation_args);
if validate != self.validate {
refresh1 = true;
field_handle.update_validate(Some(validate));
}
}
+#[derive(PartialEq)]
+pub struct ValidateClosure<T> {
+ required: bool,
+ min: Option<T>,
+ max: Option<T>,
+ validate: Option<ValidateFn<T>>,
+}
+
impl<T: NumberTypeInfo> ManagedField for NumberField<T> {
type Properties = Number<T>;
type Message = Msg;
+ type ValidateClosure = ValidateClosure<T>;
+
+ fn validation_args(props: &Self::Properties) -> Self::ValidateClosure {
+ ValidateClosure {
+ required: props.input_props.required,
+ min: props.min,
+ max: props.max,
+ validate: props.validate.clone(),
+ }
+ }
- fn validation_fn_need_update(props: &Self::Properties, old_props: &Self::Properties) -> bool {
- props.input_props.required != old_props.input_props.required
- || props.min != old_props.min
- || props.max != old_props.max
- || props.validate != old_props.validate
- }
-
- fn create_validation_fn(props: &Number<T>) -> ValidateFn<Value> {
- let props = props.clone();
+ fn create_validation_fn(props: Self::ValidateClosure) -> ValidateFn<Value> {
ValidateFn::new(move |value: &Value| {
let is_empty = match value {
Value::Null => true,
};
if is_empty {
- if props.input_props.required {
+ if props.required {
return Err(Error::msg(tr!("Field may not be empty.")));
} else {
return Ok(());
}
}
+#[derive(PartialEq)]
+pub struct ValidateClosure<S: DataStore> {
+ required: bool,
+ store: S,
+ validate: Option<ValidateFn<(String, S)>>,
+}
+
impl<S: DataStore + 'static> ManagedField for SelectorField<S> {
type Message = Msg<S>;
type Properties = Selector<S>;
+ type ValidateClosure = ValidateClosure<S>;
- fn validation_fn_need_update(props: &Self::Properties, old_props: &Self::Properties) -> bool {
- props.input_props.required != old_props.input_props.required
- || props.store != old_props.store
- || props.validate != old_props.validate
+ fn validation_args(props: &Self::Properties) -> Self::ValidateClosure {
+ ValidateClosure {
+ required: props.input_props.required,
+ store: props.store.clone(),
+ validate: props.validate.clone(),
+ }
}
- fn create_validation_fn(props: &Selector<S>) -> ValidateFn<Value> {
- let store = props.store.clone();
- let required = props.input_props.required;
- let validate = props.validate.clone();
+ fn create_validation_fn(props: Self::ValidateClosure) -> ValidateFn<Value> {
+
ValidateFn::new(move |value: &Value| {
let value = match value {
Value::Null => String::new(),
};
if value.is_empty() {
- if required {
+ if props.required {
bail!("Field may not be empty.");
} else {
return Ok(());
}
}
- if !store.is_empty() {
- match &validate {
- Some(cb) => cb.validate(&(value.into(), store.clone())),
+ if !props.store.is_empty() {
+ match &props.validate {
+ Some(cb) => cb.validate(&(value.into(), props.store.clone())),
None => Ok(()),
}
} else {
}
}
+#[derive(PartialEq)]
+pub struct ValidateClosure {
+ required: bool,
+ validate: Option<ValidateFn<String>>,
+}
+
impl ManagedField for TextAreaField {
type Properties = TextArea;
type Message = Msg;
+ type ValidateClosure = ValidateClosure;
+
+ fn validation_args(props: &Self::Properties) -> Self::ValidateClosure {
+ ValidateClosure {
+ required: props.input_props.required,
+ validate: props.validate.clone(),
+ }
+ }
- fn create_validation_fn(props: &TextArea) -> ValidateFn<Value> {
- let input_props = props.input_props.clone();
- let validate = props.validate.clone();
+ fn create_validation_fn(props: ValidateClosure) -> ValidateFn<Value> {
ValidateFn::new(move |value: &Value| {
let value = match value {
Value::Null => String::new(),
};
if value.is_empty() {
- if input_props.required {
+ if props.required {
return Err(Error::msg(tr!("Field may not be empty.")));
} else {
return Ok(());
}
}
- match &validate {
+ match &props.validate {
Some(cb) => cb.validate(&value),
None => Ok(()),
}
impl ManagedField for PwtTristateBoolean {
type Message = Msg;
type Properties = TristateBoolean;
+ type ValidateClosure = ();
- fn validation_fn_need_update(_props: &Self::Properties, _old_props: &Self::Properties) -> bool {
- false
- }
+ fn validation_args(_props: &Self::Properties) -> Self::ValidateClosure { () }
- fn create_validation_fn(_props: &Self::Properties) -> ValidateFn<Value> {
+ fn create_validation_fn(_props: Self::ValidateClosure) -> ValidateFn<Value> {
ValidateFn::new(move |value: &Value| match value {
Value::Null | Value::Bool(_) => Ok(()),
_ => Err(Error::msg(tr!("Got wrong data type!"))),
impl ManagedField for MenuCheckboxField {
type Message = Msg;
type Properties = MenuCheckbox;
+ type ValidateClosure = ();
+
+ fn validation_args(_props: &Self::Properties) -> Self::ValidateClosure { () }
fn setup(props: &MenuCheckbox) -> ManagedFieldState {
let on_value = props.value.as_deref().unwrap_or("on").to_string();