feat: form works in web

This commit is contained in:
Jonathan Kelley 2022-02-04 02:13:35 -05:00
parent add21d5f9d
commit d758dc6065
2 changed files with 31 additions and 25 deletions

View file

@ -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::*; use dioxus::prelude::*;
@ -13,7 +14,7 @@ fn app(cx: Scope) -> Element {
div { div {
h1 { "Form" } h1 { "Form" }
form { form {
oninput: move |ev| println!("{:?}", ev), oninput: move |ev| println!("{:?}", ev.values),
input { r#type: "text", name: "username" } input { r#type: "text", name: "username" }
input { r#type: "text", name: "full-name" } input { r#type: "text", name: "full-name" }
input { r#type: "password", name: "password" } input { r#type: "password", name: "password" }

View file

@ -41,7 +41,7 @@ impl WebsysDom {
Some(Ok(id)) => { Some(Ok(id)) => {
break Ok(UserEvent { break Ok(UserEvent {
name: event_name_from_typ(&typ), 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)), element: Some(ElementId(id)),
scope_id: None, scope_id: None,
priority: dioxus_core::EventPriority::Medium, priority: dioxus_core::EventPriority::Medium,
@ -57,7 +57,10 @@ impl WebsysDom {
} else { } else {
break Ok(UserEvent { break Ok(UserEvent {
name: event_name_from_typ(&typ), 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, element: None,
scope_id: None, scope_id: None,
priority: dioxus_core::EventPriority::Low, 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. // 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. // 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::on::*;
use dioxus_html::KeyCode; 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 // 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 // don't have a good solution with the serialized event problem
"change" | "input" | "invalid" | "reset" | "submit" => { "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) let value: String = (&target)
.dyn_ref() .dyn_ref()
.map(|input: &web_sys::HtmlInputElement| { .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(); let mut values = std::collections::HashMap::new();
// try to fill in form values
if let Some(form) = target.dyn_ref::<web_sys::HtmlFormElement>() { if let Some(form) = target.dyn_ref::<web_sys::HtmlFormElement>() {
let elements = form.elements(); let elements = form.elements();
for x in 0..elements.length() { for x in 0..elements.length() {
let element = elements.item(x).unwrap(); let element = elements.item(x).unwrap();
if let Some(name) = element.get_attribute("name") { if let Some(name) = element.get_attribute("name") {
let value: String = (&element) let value: String = (&element)
.dyn_ref() .dyn_ref()
.map(|input: &web_sys::HtmlInputElement| { .map(|input: &web_sys::HtmlInputElement| {
match input.type_().as_str() { match input.type_().as_str() {
"checkbox" => { "checkbox" => {
match input.checked() { match input.checked() {
true => "true".to_string(), true => "true".to_string(),
false => "false".to_string(), false => "false".to_string(),
} }
}, },
_ => input.value() _ => input.value()
} }
}) })
.or_else(|| target.dyn_ref().map(|input: &web_sys::HtmlTextAreaElement| 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().map(|input: &web_sys::HtmlSelectElement| input.value()))
.or_else(|| target.dyn_ref::<web_sys::HtmlElement>().unwrap().text_content()) .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"); .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
values.insert(name, value); 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" | "playing" | "progress" | "ratechange" | "seeked" | "seeking" | "stalled" | "suspend"
| "timeupdate" | "volumechange" | "waiting" => Arc::new(MediaData {}), | "timeupdate" | "volumechange" | "waiting" => Arc::new(MediaData {}),
"toggle" => Arc::new(ToggleData {}), "toggle" => Arc::new(ToggleData {}),
_ => Arc::new(()), _ => Arc::new(()),
} }
} }