浏览代码

1. remove value_types from FormData.
2. modify type of values to accept dynamic type.

Bunny Bites 1 年之前
父节点
当前提交
c6b39c05b7

+ 6 - 63
packages/html/src/events/form.rs

@@ -1,13 +1,13 @@
 use std::{any::Any, collections::HashMap, fmt::Debug};
 
 use dioxus_core::Event;
-use serde::{de::Error, Deserialize, Serialize};
+use serde::{Deserialize, Serialize};
 
 pub type FormEvent = Event<FormData>;
 
-#[derive(Serialize, Deserialize, Debug)]
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
 #[serde(untagged)] // this will serialize Text(String) -> String and VecText(Vec<String>) to Vec<String>
-enum ValueType {
+pub enum ValueType {
     Text(String),
     VecText(Vec<String>),
 }
@@ -18,9 +18,7 @@ enum ValueType {
 pub struct FormData {
     pub value: String,
 
-    pub values: HashMap<String, Vec<String>>,
-
-    pub value_types: HashMap<String, String>,
+    pub values: HashMap<String, ValueType>,
 
     #[cfg_attr(
         feature = "serialize",
@@ -42,67 +40,12 @@ where
 }
 
 impl FormData {
-    // ***** function to parse the 'values' to make it ready to use*******
-    // e.g - self.values = { username: ["rust"], password: ["dioxus"]}
-    // what we need it to be: { username: "rust", password: "dioxus"}
-    fn get_parsed_values(&self) -> Result<String, serde_json::Error> {
-        if self.values.is_empty() {
-            return Err(serde_json::Error::custom("Values array is empty"));
-        }
-
-        let raw_values = self.values.clone();
-
-        let mut parsed_values: HashMap<String, ValueType> = HashMap::new();
-
-        for (fieldname, values) in raw_values.into_iter() {
-            // check if the fieldname can hold multiple values based on its types
-            let field_type = self
-                .value_types
-                .get(&fieldname)
-                .expect("Provided invalid field");
-
-            let is_multi_valued_input = match field_type.as_str() {
-                "select" | "checkbox" => true,
-                _ => false,
-            };
-
-            /*
-            case 1 - multiple values, example { driving_types: ["manual", "automatic"] }
-                In this case we want to return the values as it is, NO point in making
-                driving_types: "manual, automatic"
-
-            case 2 - single value, example { favourite_language: ["rust"] }
-                In this case we would want to deserialize the value as follows
-                favourite_language: "rust"
-            */
-            parsed_values.insert(
-                fieldname,
-                if is_multi_valued_input {
-                    // handling multiple values - case 1
-                    ValueType::VecText(values)
-                } else {
-                    // handle single value - case 2
-                    ValueType::Text(
-                        values
-                            .into_iter()
-                            .next()
-                            .ok_or_else(|| serde_json::Error::custom("Values array is empty"))?,
-                    )
-                },
-            );
-        }
-
-        // convert HashMap to JSON string
-        convert_hashmap_to_json(&parsed_values)
-    }
-
     pub fn parse_json<T>(&self) -> Result<T, serde_json::Error>
     where
         T: serde::de::DeserializeOwned,
     {
-        let parsed_json = self
-            .get_parsed_values()
-            .expect("Failed to parse values to JSON");
+        let parsed_json =
+            convert_hashmap_to_json(&self.values.clone()).expect("Failed to parse values to JSON");
 
         serde_json::from_str(&parsed_json)
     }

+ 1 - 4
packages/rink/src/hooks.rs

@@ -61,9 +61,7 @@ impl EventData {
 pub struct FormData {
     pub value: String,
 
-    pub values: HashMap<String, Vec<String>>,
-
-    pub value_types: HashMap<String, String>,
+    pub values: HashMap<String, ValueType>,
 
     pub files: Option<Files>,
 }
@@ -73,7 +71,6 @@ impl FormData {
         dioxus_html::FormData {
             value: self.value,
             values: self.values,
-            value_types: self.value_types,
             files: None,
         }
     }

+ 0 - 1
packages/rink/src/widgets/button.rs

@@ -93,7 +93,6 @@ impl Button {
         let data = FormData {
             value: self.value.to_string(),
             values: HashMap::new(),
-            value_types: HashMap::new(),
             files: None,
         };
         ctx.send(crate::Event {

+ 0 - 1
packages/rink/src/widgets/slider.rs

@@ -198,7 +198,6 @@ impl Slider {
             let data = FormData {
                 value: self.value.to_string(),
                 values: HashMap::new(),
-                value_types: HashMap::new(),
                 files: None,
             };
             ctx.send(Event {

+ 0 - 1
packages/rink/src/widgets/text_like.rs

@@ -171,7 +171,6 @@ impl<C: TextLikeController> TextLike<C> {
             let data: FormData = FormData {
                 value: self.text.clone(),
                 values: HashMap::new(),
-                value_types: HashMap::new(),
                 files: None,
             };
             let ctx: UniqueView<WidgetContext> = world.borrow().expect("expected widget context");

+ 19 - 21
packages/web/src/dom.rs

@@ -10,7 +10,7 @@
 use dioxus_core::{
     BorrowedAttributeValue, ElementId, Mutation, Template, TemplateAttribute, TemplateNode,
 };
-use dioxus_html::{event_bubbles, CompositionData, FormData, MountedData};
+use dioxus_html::{event_bubbles, CompositionData, FormData, MountedData, ValueType};
 use dioxus_interpreter_js::{get_node, minimal_bindings, save_template, Channel};
 use futures_channel::mpsc;
 use js_sys::Array;
@@ -365,22 +365,7 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
         })
         .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
 
-    let mut value_types = HashMap::new();
-
-    // to get the input_type for the corresponding input
-    for input_el in target.dyn_ref::<web_sys::HtmlFormElement>().into_iter() {
-        for index in 0..input_el.length() {
-            if let Some(element) = input_el.get_with_index(index as u32) {
-                if let Some(input) = element.dyn_into::<web_sys::HtmlInputElement>().ok() {
-                    let name = input.name();
-                    let input_type = input.type_();
-                    value_types.insert(name, input_type);
-                }
-            }
-        }
-    }
-
-    let mut values = std::collections::HashMap::new();
+    let mut values = HashMap::new();
 
     // try to fill in form values
     if let Some(form) = target.dyn_ref::<web_sys::HtmlFormElement>() {
@@ -389,10 +374,12 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
             if let Ok(array) = value.dyn_into::<Array>() {
                 if let Some(name) = array.get(0).as_string() {
                     if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
-                        let item_values =
+                        let item_values: Vec<String> =
                             item_values.iter().filter_map(|v| v.as_string()).collect();
 
-                        values.insert(name, item_values);
+                        values.insert(name, ValueType::VecText(item_values));
+                    } else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
+                        values.insert(name, ValueType::Text(item_value.as_string().unwrap()));
                     }
                 }
             }
@@ -415,7 +402,6 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
     Rc::new(FormData {
         value,
         values,
-        value_types,
         files,
     })
 }
@@ -424,10 +410,22 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
 #[wasm_bindgen(inline_js = r#"
     export function get_form_data(form) {
         let values = new Map();
+
         const formData = new FormData(form);
 
         for (let name of formData.keys()) {
-            values.set(name, formData.getAll(name));
+            const fieldType = form.elements[name].type;
+
+            switch (fieldType) {
+                case "select-multiple":
+                    values.set(name, formData.getAll(name));
+                    break;
+
+                // add cases for fieldTypes that can hold multiple values here
+                default:
+                    values.set(name, formData.get(name));
+                    break;
+            }
         }
 
         return values;