瀏覽代碼

Merge pull request #1836 from serzhiio/master

Aggregating input values into arrays if required
ealmloff 1 年之前
父節點
當前提交
6126e02143
共有 2 個文件被更改,包括 59 次插入23 次删除
  1. 32 0
      packages/html/src/events/form.rs
  2. 27 23
      packages/web/src/event.rs

+ 32 - 0
packages/html/src/events/form.rs

@@ -1,5 +1,6 @@
 use crate::file_data::FileEngine;
 use crate::file_data::HasFileData;
+use std::ops::Deref;
 use std::{collections::HashMap, fmt::Debug};
 
 use dioxus_core::Event;
@@ -19,6 +20,37 @@ pub enum FormValue {
     VecText(Vec<String>),
 }
 
+impl From<FormValue> for Vec<String> {
+    fn from(value: FormValue) -> Self {
+        match value {
+            FormValue::Text(s) => vec![s],
+            FormValue::VecText(vec) => vec,
+        }
+    }
+}
+
+impl Deref for FormValue {
+    type Target = [String];
+
+    fn deref(&self) -> &Self::Target {
+        self.as_slice()
+    }
+}
+
+impl FormValue {
+    /// Convenient way to represent Value as slice
+    pub fn as_slice(&self) -> &[String] {
+        match self {
+            FormValue::Text(s) => std::slice::from_ref(s),
+            FormValue::VecText(vec) => vec.as_slice(),
+        }
+    }
+    /// Convert into Vec<String>
+    pub fn to_vec(self) -> Vec<String> {
+        self.into()
+    }
+}
+
 /* DOMEvent:  Send + SyncTarget relatedTarget */
 pub struct FormData {
     inner: Box<dyn HasFormData>,

+ 27 - 23
packages/web/src/event.rs

@@ -389,7 +389,25 @@ impl HasFormData for WebFormData {
     }
 
     fn values(&self) -> HashMap<String, FormValue> {
-        let mut values = std::collections::HashMap::new();
+        let mut values = HashMap::new();
+
+        fn insert_value(map: &mut HashMap<String, FormValue>, key: String, new_value: String) {
+            match map.entry(key) {
+                std::collections::hash_map::Entry::Occupied(mut o) => {
+                    let first_value = match o.get_mut() {
+                        FormValue::Text(data) => std::mem::take(data),
+                        FormValue::VecText(vec) => {
+                            vec.push(new_value);
+                            return;
+                        }
+                    };
+                    let _ = o.insert(FormValue::VecText(vec![first_value, new_value]));
+                }
+                std::collections::hash_map::Entry::Vacant(v) => {
+                    let _ = v.insert(FormValue::Text(new_value));
+                }
+            }
+        }
 
         // try to fill in form values
         if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() {
@@ -398,20 +416,18 @@ impl HasFormData for WebFormData {
                 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: Vec<String> =
-                                item_values.iter().filter_map(|v| v.as_string()).collect();
-
-                            values.insert(name, FormValue::VecText(item_values));
+                            item_values
+                                .iter()
+                                .filter_map(|v| v.as_string())
+                                .for_each(|v| insert_value(&mut values, name.clone(), v));
                         } else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
-                            values.insert(name, FormValue::Text(item_value.as_string().unwrap()));
+                            insert_value(&mut values, name, item_value.as_string().unwrap());
                         }
                     }
                 }
             }
-        }
-
-        // try to fill in select element values
-        if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
+        } else if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
+            // try to fill in select element values
             let options = get_select_data(select);
             values.insert("options".to_string(), FormValue::VecText(options));
         }
@@ -536,19 +552,7 @@ export function get_form_data(form) {
     const formData = new FormData(form);
 
     for (let name of formData.keys()) {
-        const fieldType = form.elements[name].type;
-        console.log(fieldType);
-
-        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;
-        }
+        values.set(name, formData.getAll(name));
     }
 
     return values;