Browse Source

feat: form works in web

Jonathan Kelley 3 years ago
parent
commit
d758dc6065
2 changed files with 31 additions and 25 deletions
  1. 4 3
      examples/form.rs
  2. 27 22
      packages/web/src/dom.rs

+ 4 - 3
examples/form.rs

@@ -1,6 +1,7 @@
-//! Example: README.md showcase
+//! Forms
 //!
-//! The example from the README.md.
+//! Dioxus forms deviate slightly from html, automatically returning all named inputs
+//! in the "values" field
 
 use dioxus::prelude::*;
 
@@ -13,7 +14,7 @@ fn app(cx: Scope) -> Element {
         div {
             h1 { "Form" }
             form {
-                oninput: move |ev| println!("{:?}", ev),
+                oninput: move |ev| println!("{:?}", ev.values),
                 input { r#type: "text", name: "username" }
                 input { r#type: "text", name: "full-name" }
                 input { r#type: "password", name: "password" }

+ 27 - 22
packages/web/src/dom.rs

@@ -41,7 +41,7 @@ impl WebsysDom {
                     Some(Ok(id)) => {
                         break Ok(UserEvent {
                             name: event_name_from_typ(&typ),
-                            data: virtual_event_from_websys_event(event.clone()),
+                            data: virtual_event_from_websys_event(event.clone(), target.clone()),
                             element: Some(ElementId(id)),
                             scope_id: None,
                             priority: dioxus_core::EventPriority::Medium,
@@ -57,7 +57,10 @@ impl WebsysDom {
                         } else {
                             break Ok(UserEvent {
                                 name: event_name_from_typ(&typ),
-                                data: virtual_event_from_websys_event(event.clone()),
+                                data: virtual_event_from_websys_event(
+                                    event.clone(),
+                                    target.clone(),
+                                ),
                                 element: None,
                                 scope_id: None,
                                 priority: dioxus_core::EventPriority::Low,
@@ -144,7 +147,10 @@ unsafe impl Sync for DioxusWebsysEvent {}
 
 // todo: some of these events are being casted to the wrong event type.
 // We need tests that simulate clicks/etc and make sure every event type works.
-fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send + Sync> {
+fn virtual_event_from_websys_event(
+    event: web_sys::Event,
+    target: Element,
+) -> Arc<dyn Any + Send + Sync> {
     use dioxus_html::on::*;
     use dioxus_html::KeyCode;
 
@@ -177,9 +183,6 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send
         // todo: these handlers might get really slow if the input box gets large and allocation pressure is heavy
         // don't have a good solution with the serialized event problem
         "change" | "input" | "invalid" | "reset" | "submit" => {
-            let evt: &web_sys::Event = event.dyn_ref().unwrap();
-
-            let target: web_sys::EventTarget = evt.target().unwrap();
             let value: String = (&target)
                 .dyn_ref()
                 .map(|input: &web_sys::HtmlInputElement| {
@@ -217,28 +220,29 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send
 
             let mut values = std::collections::HashMap::new();
 
+            // try to fill in form values
             if let Some(form) = target.dyn_ref::<web_sys::HtmlFormElement>() {
                 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: String = (&element)
-                            .dyn_ref()
-                            .map(|input: &web_sys::HtmlInputElement| {
-                                match input.type_().as_str() {
-                                    "checkbox" => {
-                                        match input.checked() {
-                                            true => "true".to_string(),
-                                            false => "false".to_string(),
-                                        }
-                                    },
-                                    _ => input.value()
-                                }
-                            })
-                            .or_else(|| target.dyn_ref().map(|input: &web_sys::HtmlTextAreaElement| input.value()))
-                            .or_else(|| target.dyn_ref().map(|input: &web_sys::HtmlSelectElement| input.value()))
-                            .or_else(|| target.dyn_ref::<web_sys::HtmlElement>().unwrap().text_content())
-                            .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
+                                .dyn_ref()
+                                .map(|input: &web_sys::HtmlInputElement| {
+                                    match input.type_().as_str() {
+                                        "checkbox" => {
+                                            match input.checked() {
+                                                true => "true".to_string(),
+                                                false => "false".to_string(),
+                                            }
+                                        },
+                                        _ => input.value()
+                                    }
+                                })
+                                .or_else(|| target.dyn_ref().map(|input: &web_sys::HtmlTextAreaElement| input.value()))
+                                .or_else(|| target.dyn_ref().map(|input: &web_sys::HtmlSelectElement| input.value()))
+                                .or_else(|| target.dyn_ref::<web_sys::HtmlElement>().unwrap().text_content())
+                                .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
 
                         values.insert(name, value);
                     }
@@ -337,6 +341,7 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send
         | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
         | "timeupdate" | "volumechange" | "waiting" => Arc::new(MediaData {}),
         "toggle" => Arc::new(ToggleData {}),
+
         _ => Arc::new(()),
     }
 }