Fix form events with select multiple
This commit is contained in:
1 parent
61d100e1f8
commit
f1f7517b88
3 files changed
+45
-57
No files matched your search
@@ -10,7 +10,7 @@ pub type FormEvent = Event<FormData>;
|
|||||||
pub struct FormData {
|
pub struct FormData {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
|
||||||
pub values: HashMap<String, String>,
|
pub values: HashMap<String, Vec<String>>,
|
||||||
|
|
||||||
#[cfg_attr(feature = "serialize", serde(skip))]
|
#[cfg_attr(feature = "serialize", serde(skip))]
|
||||||
pub files: Option<std::sync::Arc<dyn FileEngine>>,
|
pub files: Option<std::sync::Arc<dyn FileEngine>>,
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ class ListenerMap {
|
|||||||
} else {
|
} else {
|
||||||
this.global[event_name].active++;
|
this.global[event_name].active++;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const id = element.getAttribute("data-dioxus-id");
|
const id = element.getAttribute("data-dioxus-id");
|
||||||
if (!this.local[id]) {
|
if (!this.local[id]) {
|
||||||
this.local[id] = {};
|
this.local[id] = {};
|
||||||
@@ -32,11 +31,13 @@ class ListenerMap {
|
|||||||
if (bubbles) {
|
if (bubbles) {
|
||||||
this.global[event_name].active--;
|
this.global[event_name].active--;
|
||||||
if (this.global[event_name].active === 0) {
|
if (this.global[event_name].active === 0) {
|
||||||
this.root.removeEventListener(event_name, this.global[event_name].callback);
|
this.root.removeEventListener(
|
||||||
|
event_name,
|
||||||
|
this.global[event_name].callback
|
||||||
|
);
|
||||||
delete this.global[event_name];
|
delete this.global[event_name];
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const id = element.getAttribute("data-dioxus-id");
|
const id = element.getAttribute("data-dioxus-id");
|
||||||
delete this.local[id][event_name];
|
delete this.local[id][event_name];
|
||||||
if (this.local[id].length === 0) {
|
if (this.local[id].length === 0) {
|
||||||
@@ -143,8 +144,7 @@ class Interpreter {
|
|||||||
SetAttribute(id, field, value, ns) {
|
SetAttribute(id, field, value, ns) {
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
this.RemoveAttribute(id, field, ns);
|
this.RemoveAttribute(id, field, ns);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const node = this.nodes[id];
|
const node = this.nodes[id];
|
||||||
this.SetAttributeInner(node, field, value, ns);
|
this.SetAttributeInner(node, field, value, ns);
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,6 @@ class Interpreter {
|
|||||||
this.RemoveEventListener(edit.id, edit.name);
|
this.RemoveEventListener(edit.id, edit.name);
|
||||||
break;
|
break;
|
||||||
case "NewEventListener":
|
case "NewEventListener":
|
||||||
|
|
||||||
let bubbles = event_bubbles(edit.name);
|
let bubbles = event_bubbles(edit.name);
|
||||||
|
|
||||||
// this handler is only provided on desktop implementations since this
|
// this handler is only provided on desktop implementations since this
|
||||||
@@ -360,7 +359,10 @@ class Interpreter {
|
|||||||
let a_element = target.closest("a");
|
let a_element = target.closest("a");
|
||||||
if (a_element != null) {
|
if (a_element != null) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (shouldPreventDefault !== `onclick` && a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`) {
|
if (
|
||||||
|
shouldPreventDefault !== `onclick` &&
|
||||||
|
a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`
|
||||||
|
) {
|
||||||
const href = a_element.getAttribute("href");
|
const href = a_element.getAttribute("href");
|
||||||
if (href !== "" && href !== null && href !== undefined) {
|
if (href !== "" && href !== null && href !== undefined) {
|
||||||
window.ipc.postMessage(
|
window.ipc.postMessage(
|
||||||
@@ -404,23 +406,10 @@ class Interpreter {
|
|||||||
target.tagName === "FORM" &&
|
target.tagName === "FORM" &&
|
||||||
(event.type === "submit" || event.type === "input")
|
(event.type === "submit" || event.type === "input")
|
||||||
) {
|
) {
|
||||||
for (let x = 0; x < target.elements.length; x++) {
|
const formData = new FormData(target);
|
||||||
let element = target.elements[x];
|
|
||||||
let name = element.getAttribute("name");
|
for (let name of formData.keys()) {
|
||||||
if (name != null) {
|
contents.values[name] = formData.getAll(name);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-30
@@ -13,9 +13,10 @@ use dioxus_core::{
|
|||||||
use dioxus_html::{event_bubbles, CompositionData, FormData};
|
use dioxus_html::{event_bubbles, CompositionData, FormData};
|
||||||
use dioxus_interpreter_js::{save_template, Channel};
|
use dioxus_interpreter_js::{save_template, Channel};
|
||||||
use futures_channel::mpsc;
|
use futures_channel::mpsc;
|
||||||
|
use js_sys::Array;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::{any::Any, rc::Rc};
|
use std::{any::Any, rc::Rc};
|
||||||
use wasm_bindgen::{closure::Closure, JsCast};
|
use wasm_bindgen::{closure::Closure, prelude::wasm_bindgen, JsCast};
|
||||||
use web_sys::{Document, Element, Event, HtmlElement};
|
use web_sys::{Document, Element, Event, HtmlElement};
|
||||||
|
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
@@ -325,35 +326,16 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
|
|||||||
|
|
||||||
// try to fill in form values
|
// 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 form_data = get_form_data(form);
|
||||||
for x in 0..elements.length() {
|
for value in form_data.entries().into_iter().flatten() {
|
||||||
let element = elements.item(x).unwrap();
|
if let Ok(array) = value.dyn_into::<Array>() {
|
||||||
if let Some(name) = element.get_attribute("name") {
|
if let Some(name) = array.get(0).as_string() {
|
||||||
let value: Option<String> = element
|
if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
|
||||||
.dyn_ref()
|
let item_values =
|
||||||
.map(|input: &web_sys::HtmlInputElement| {
|
item_values.iter().filter_map(|v| v.as_string()).collect();
|
||||||
match input.type_().as_str() {
|
|
||||||
"checkbox" => {
|
values.insert(name, item_values);
|
||||||
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::<web_sys::HtmlElement>().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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,6 +348,23 @@ fn read_input_to_data(target: Element) -> Rc<FormData> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)> {
|
fn walk_event_for_id(event: &web_sys::Event) -> Option<(ElementId, web_sys::Element)> {
|
||||||
let mut target = event
|
let mut target = event
|
||||||
.target()
|
.target()
|
||||||
|
|||||||
Reference in new issue
Block a user