From bb71b5db61448dbc226911e1beee5e9eacb22719 Mon Sep 17 00:00:00 2001 From: WorldSEnder Date: Sat, 8 Oct 2022 17:50:19 +0200 Subject: [PATCH] Fix checked property being reset (#2907) if the value is uncontrolled, do not touch it. Only if it is explicitly given --- .../yew-macro/src/html_tree/html_element.rs | 4 +-- .../yew/src/dom_bundle/btag/attributes.rs | 12 +++++--- packages/yew/src/virtual_dom/vtag.rs | 29 +++++++++++++------ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index 408a260ab13..7991873b354 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -128,9 +128,9 @@ impl ToTokens for HtmlElement { .as_ref() .map(|attr| { let value = &attr.value; - quote_spanned! {value.span()=> #value} + quote! { ::std::option::Option::Some( #value ) } }) - .unwrap_or(quote! { false }); + .unwrap_or(quote! { ::std::option::Option::None }); // other attributes diff --git a/packages/yew/src/dom_bundle/btag/attributes.rs b/packages/yew/src/dom_bundle/btag/attributes.rs index 7cfa0a5224d..7731969cd46 100644 --- a/packages/yew/src/dom_bundle/btag/attributes.rs +++ b/packages/yew/src/dom_bundle/btag/attributes.rs @@ -67,18 +67,22 @@ impl Apply for InputFields { type Element = InputElement; fn apply(mut self, root: &BSubtree, el: &Self::Element) -> Self { - // IMPORTANT! This parameter has to be set every time + // IMPORTANT! This parameter has to be set every time it's explicitly given // to prevent strange behaviour in the browser when the DOM changes - el.set_checked(self.checked); + if let Some(checked) = self.checked { + el.set_checked(checked); + } self.value = self.value.apply(root, el); self } fn apply_diff(self, root: &BSubtree, el: &Self::Element, bundle: &mut Self) { - // IMPORTANT! This parameter has to be set every time + // IMPORTANT! This parameter has to be set every time it's explicitly given // to prevent strange behaviour in the browser when the DOM changes - el.set_checked(self.checked); + if let Some(checked) = self.checked { + el.set_checked(checked); + } self.value.apply_diff(root, el, &mut bundle.value); } diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 4e4e5fc88f8..c54011d5765 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -62,7 +62,7 @@ pub(crate) struct InputFields { /// It exists to override standard behavior of `checked` attribute, because /// in original HTML it sets `defaultChecked` value of `InputElement`, but for reactive /// frameworks it's more useful to control `checked` value of an `InputElement`. - pub(crate) checked: bool, + pub(crate) checked: Option, } impl Deref for InputFields { @@ -81,7 +81,7 @@ impl DerefMut for InputFields { impl InputFields { /// Crate new attributes for an [InputElement] element - fn new(value: Option, checked: bool) -> Self { + fn new(value: Option, checked: Option) -> Self { Self { value: Value::new(value), checked, @@ -164,7 +164,7 @@ impl VTag { #[allow(clippy::too_many_arguments)] pub fn __new_input( value: Option, - checked: bool, + checked: Option, node_ref: NodeRef, key: Option, // at bottom for more readable macro-expanded coded @@ -341,20 +341,29 @@ impl VTag { /// Returns `checked` property of an /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). - /// (Not a value of node's attribute). - pub fn checked(&self) -> bool { + /// (Does not affect the value of the node's attribute). + pub fn checked(&self) -> Option { match &self.inner { VTagInner::Input(f) => f.checked, - _ => false, + _ => None, } } /// Sets `checked` property of an /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). - /// (Not a value of node's attribute). + /// (Does not affect the value of the node's attribute). pub fn set_checked(&mut self, value: bool) { if let VTagInner::Input(f) = &mut self.inner { - f.checked = value; + f.checked = Some(value); + } + } + + /// Keeps the current value of the `checked` property of an + /// [InputElement](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). + /// (Does not affect the value of the node's attribute). + pub fn preserve_checked(&mut self) { + if let VTagInner::Input(f) = &mut self.inner { + f.checked = None; } } @@ -479,7 +488,9 @@ mod feat_ssr { write_attr(w, "value", Some(m)); } - if self.checked() { + // Setting is as an attribute sets the `defaultChecked` property. Only emit this + // if it's explicitly set to checked. + if self.checked() == Some(true) { write_attr(w, "checked", None); } }