feat: prevent short-circuit evaluation for validation

This commit is contained in:
alphafetus committed 2026-01-05 15:20:04 -05:00
1 parent f08fee1246
commit e0b54b96f9
3 files changed
+37 -20

No files matched your search

+21 -14
View File
@@ -11,27 +11,27 @@ use std::collections::HashMap;
pub enum InputType { pub enum InputType {
/// Represents a text input. Requires a `String` key, `String` label, and `String` placeholder. /// Represents a text input. Requires a `String` key, `String` label, and `String` placeholder.
/// The entered value will be returned as a single `String` value. /// The entered value will be returned as a single `String` value.
Text(String, String, String), Text(String, String, String, bool),
/// Represents a number input. Requires a `String` key, `String` label, and a `String` placeholder. /// Represents a number input. Requires a `String` key, `String` label, and a `String` placeholder.
/// The entered value will be returned as a `String`, and will be parseable into any number type /// The entered value will be returned as a `String`, and will be parseable into any number type
/// (i.e. an `i32`, `i64`, etc) /// (i.e. an `i32`, `i64`, etc)
Number(String, String, String), Number(String, String, String, bool),
/// Represents a radio input. Requires a `String` key, `String` label, and a series of `String` /// Represents a radio input. Requires a `String` key, `String` label, and a series of `String`
/// options. The selected value will be returned as a `String`. /// options. The selected value will be returned as a `String`.
Radio(String, String, Vec<String>), Radio(String, String, Vec<String>, bool),
/// Represents a checkbox input. Requires a `String` key, `String` label, and a series of `String` /// Represents a checkbox input. Requires a `String` key, `String` label, and a series of `String`
/// options. The selected values will be returned as a `Vec<String>`. /// options. The selected values will be returned as a `Vec<String>`.
Checkbox(String, String, Vec<String>), Checkbox(String, String, Vec<String>, bool),
/// Represents a dropdown input. Requires a `String` key, `String` label, and a series /// Represents a dropdown input. Requires a `String` key, `String` label, and a series
/// of `String` options. The selected value will be returned as a `String`. /// of `String` options. The selected value will be returned as a `String`.
Select(String, String, Vec<String>), Select(String, String, Vec<String>, bool),
} }
impl InputType { impl InputType {
pub fn into_view(self, data_map: RwSignal<HashMap<String, ValueType>>) -> impl IntoView { pub fn into_view(self, data_map: RwSignal<HashMap<String, ValueType>>) -> impl IntoView {
view! { view! {
{match self { {match self {
InputType::Text(member, label, placeholder) => InputType::Text(member, label, placeholder, required) =>
EitherOf5::A(view! { EitherOf5::A(view! {
<Row> <Row>
<OutlinedTextField <OutlinedTextField
@@ -39,10 +39,11 @@ impl InputType {
placeholder = placeholder.clone() placeholder = placeholder.clone()
data_member = member.clone() data_member = member.clone()
data_map = data_map data_map = data_map
required = required
/> />
</Row> </Row>
}), }),
InputType::Number(member, label, placeholder) => InputType::Number(member, label, placeholder, required) =>
EitherOf5::B(view! { EitherOf5::B(view! {
<OutlinedTextField <OutlinedTextField
label = label.clone() label = label.clone()
@@ -50,33 +51,37 @@ impl InputType {
data_member = member.clone() data_member = member.clone()
data_map = data_map data_map = data_map
input_type = TextFieldType::Number input_type = TextFieldType::Number
required = required
/> />
}), }),
InputType::Checkbox(member, label, options) => InputType::Checkbox(member, label, options, required) =>
EitherOf5::C(view! { EitherOf5::C(view! {
<CheckboxList <CheckboxList
label = label.clone() label = label.clone()
items = options.clone() items = options.clone()
data_member = member.clone() data_member = member.clone()
data_map = data_map data_map = data_map
required = required
/> />
}), }),
InputType::Radio(member, label, options) => InputType::Radio(member, label, options, required) =>
EitherOf5::D(view! { EitherOf5::D(view! {
<RadioList <RadioList
label = label.clone() label = label.clone()
data_member = member.clone() data_member = member.clone()
data_map = data_map data_map = data_map
items = options.clone() items = options.clone()
required = required
/> />
}), }),
InputType::Select(member, label, options) => InputType::Select(member, label, options, required) =>
EitherOf5::E(view! { EitherOf5::E(view! {
<Select <Select
label = label.clone() label = label.clone()
value_list = options.clone() value_list = options.clone()
data_member = member.clone() data_member = member.clone()
data_map = data_map data_map = data_map
required = required
/> />
}) })
}} }}
@@ -104,19 +109,21 @@ impl InputType {
/// ``` /// ```
#[macro_export] #[macro_export]
macro_rules! input { macro_rules! input {
($variant:ident, $key:expr, $label:expr, [$($option:expr),* $(,)?]) => { ($variant:ident, $key:expr, $label:expr, $required:expr, [$($option:expr),* $(,)?]) => {
$crate::common::InputType::$variant( $crate::common::InputType::$variant(
$key.to_string(), $key.to_string(),
$label.to_string(), $label.to_string(),
vec![$($option.to_string()), *] vec![$($option.to_string()), *],
$required
) )
}; };
($variant:ident, $key:expr, $label:expr, $placeholder:expr) => { ($variant:ident, $key:expr, $label:expr, $required:expr, $placeholder:expr) => {
$crate::common::InputType::$variant( $crate::common::InputType::$variant(
$key.to_string(), $key.to_string(),
$label.to_string(), $label.to_string(),
$placeholder.to_string() $placeholder.to_string(),
$required
) )
}; };
} }
+8 -4
View File
@@ -115,12 +115,16 @@ pub fn ValidatedForm(
.with(|list| { .with(|list| {
list.iter() list.iter()
// TODO all() short circuits on the first false // TODO all() short circuits on the first false
.all(|v| { .fold(true, |acc, v| {
// Not sure how this will work reactively.
let result = matches!(v.get().error().get(), ValidationState::Valid);
v.update(|validator| validator.form_requested_validation.set(true)); v.update(|validator| validator.form_requested_validation.set(true));
result matches!(v.get().error().get(), ValidationState::Valid) && acc
}) })
// .all(|v| {
// // Not sure how this will work reactively.
// let result = matches!(v.get().error().get(), ValidationState::Valid);
// v.update(|validator| validator.form_requested_validation.set(true));
// result
// })
}) })
}); });
+8 -2
View File
@@ -240,6 +240,7 @@ pub fn HomePage() -> impl IntoView {
disabled=elements_disabled disabled=elements_disabled
data_member="first_name" data_member="first_name"
data_map=form_data data_map=form_data
required=true
/> />
<OutlinedTextField <OutlinedTextField
label="Last Name:" label="Last Name:"
@@ -247,6 +248,7 @@ pub fn HomePage() -> impl IntoView {
disabled=elements_disabled disabled=elements_disabled
data_member="last_name" data_member="last_name"
data_map=form_data data_map=form_data
required=true
/> />
</Row> </Row>
<Row> <Row>
@@ -257,6 +259,7 @@ pub fn HomePage() -> impl IntoView {
data_member="contact_email" data_member="contact_email"
data_map=form_data data_map=form_data
input_type=TextFieldType::Email input_type=TextFieldType::Email
required=true
/> />
</Row> </Row>
<Row> <Row>
@@ -266,6 +269,7 @@ pub fn HomePage() -> impl IntoView {
disabled=elements_disabled disabled=elements_disabled
data_member="phone_number" data_member="phone_number"
data_map=form_data data_map=form_data
required=true
/> />
</Row> </Row>
<Row> <Row>
@@ -275,6 +279,7 @@ pub fn HomePage() -> impl IntoView {
disabled=elements_disabled disabled=elements_disabled
data_member="address" data_member="address"
data_map=form_data data_map=form_data
required=true
/> />
</Row> </Row>
<Row> <Row>
@@ -285,6 +290,7 @@ pub fn HomePage() -> impl IntoView {
data_member="math_sat" data_member="math_sat"
data_map=form_data data_map=form_data
input_type=TextFieldType::Number input_type=TextFieldType::Number
required=true
/> />
</Row> </Row>
<Row> <Row>
@@ -332,8 +338,8 @@ pub fn HomePage() -> impl IntoView {
data_map=form_data data_map=form_data
data_member="community_involvement" data_member="community_involvement"
schema=vec![ schema=vec![
input!(Text, "service_name", "Activity Name:", "Some service activity..."), input!(Text, "service_name", "Activity Name:", true, "Some service activity..."),
input!(Number, "service_hours", "Total Service Hours", "20") input!(Number, "service_hours", "Total Service Hours", true, "20")
] ]
/> />
</Row> </Row>