diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 361ebe2d4..6edf60448 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -10,7 +10,7 @@ pub type FormEvent = Event; pub struct FormData { pub value: String, - pub values: HashMap, + pub values: HashMap>, #[cfg_attr(feature = "serialize", serde(skip))] pub files: Option>, diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index db453bcda..162d5c8f5 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -345,6 +345,7 @@ class Interpreter { break; case "NewEventListener": let bubbles = event_bubbles(edit.name); + this.NewEventListener(edit.name, edit.id, bubbles, handler); break; } @@ -354,7 +355,6 @@ class Interpreter { // this handler is only provided on desktop implementations since this // method is not used by the web implementation function handler(event) { - console.log(event); let target = event.target; if (target != null) { let shouldPreventDefault = target.getAttribute(`dioxus-prevent-default`); @@ -401,21 +401,14 @@ function handler(event) { target.tagName === "FORM" && (event.type === "submit" || event.type === "input") ) { - for (let x = 0; x < target.elements.length; x++) { - let element = target.elements[x]; - let name = element.getAttribute("name"); - if (name != null) { - if (element.getAttribute("type") === "checkbox") { - // @ts-ignore - contents.values[name] = element.checked ? "true" : "false"; - } else if (element.getAttribute("type") === "radio") { - if (element.checked) { - contents.values[name] = element.value; - } - } else { - // @ts-ignore - contents.values[name] = element.value ?? element.textContent; - } + if ( + target.tagName === "FORM" && + (event.type === "submit" || event.type === "input") + ) { + const formData = new FormData(target); + + for (let name of formData.keys()) { + contents.values[name] = formData.getAll(name); } } } diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index e792c977d..e1e3b6365 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -13,9 +13,10 @@ use dioxus_core::{ use dioxus_html::{event_bubbles, CompositionData, FileEngine, FormData}; use dioxus_interpreter_js::{save_template, Channel}; use futures_channel::mpsc; +use js_sys::Array; use rustc_hash::FxHashMap; use std::{any::Any, rc::Rc, sync::Arc}; -use wasm_bindgen::{closure::Closure, JsCast}; +use wasm_bindgen::{closure::Closure, prelude::wasm_bindgen, JsCast}; use web_sys::{console, Document, Element, Event, HtmlElement}; use crate::{file_engine::WebFileEngine, Config}; @@ -327,35 +328,16 @@ fn read_input_to_data(target: Element) -> Rc { // try to fill in form values if let Some(form) = target.dyn_ref::() { - let elements = form.elements(); - for x in 0..elements.length() { - let element = elements.item(x).unwrap(); - if let Some(name) = element.get_attribute("name") { - let value: Option = element - .dyn_ref() - .map(|input: &web_sys::HtmlInputElement| { - match input.type_().as_str() { - "checkbox" => { - match input.checked() { - true => Some("true".to_string()), - false => Some("false".to_string()), - } - }, - "radio" => { - match input.checked() { - true => Some(input.value()), - false => None, - } - } - _ => Some(input.value()) - } - }) - .or_else(|| element.dyn_ref().map(|input: &web_sys::HtmlTextAreaElement| Some(input.value()))) - .or_else(|| element.dyn_ref().map(|input: &web_sys::HtmlSelectElement| Some(input.value()))) - .or_else(|| Some(element.dyn_ref::().unwrap().text_content())) - .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener"); - if let Some(value) = value { - values.insert(name, value); + let form_data = get_form_data(form); + for value in form_data.entries().into_iter().flatten() { + if let Ok(array) = value.dyn_into::() { + if let Some(name) = array.get(0).as_string() { + if let Ok(item_values) = array.get(1).dyn_into::() { + let item_values = + item_values.iter().filter_map(|v| v.as_string()).collect(); + + values.insert(name, item_values); + } } } } @@ -376,6 +358,23 @@ fn read_input_to_data(target: Element) -> Rc { }) } +// web-sys does not expose the keys api for form data, so we need to manually bind to it +#[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)); + } + + return values; + } +"#)] +extern "C" { + fn get_form_data(form: &web_sys::HtmlFormElement) -> js_sys::Map; +} + fn walk_event_for_id(event: &web_sys::Event) -> Option<(ElementId, web_sys::Element)> { let mut target = event .target()