Skip to content

Commit

Permalink
Fix checked property being reset (#2907)
Browse files Browse the repository at this point in the history
if the value is uncontrolled, do not touch it. Only if it is explicitly given
  • Loading branch information
WorldSEnder committed Oct 8, 2022
1 parent 426a1fd commit bb71b5d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 15 deletions.
4 changes: 2 additions & 2 deletions packages/yew-macro/src/html_tree/html_element.rs
Expand Up @@ -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

Expand Down
12 changes: 8 additions & 4 deletions packages/yew/src/dom_bundle/btag/attributes.rs
Expand Up @@ -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);
}
Expand Down
29 changes: 20 additions & 9 deletions packages/yew/src/virtual_dom/vtag.rs
Expand Up @@ -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<bool>,
}

impl Deref for InputFields {
Expand All @@ -81,7 +81,7 @@ impl DerefMut for InputFields {

impl InputFields {
/// Crate new attributes for an [InputElement] element
fn new(value: Option<AttrValue>, checked: bool) -> Self {
fn new(value: Option<AttrValue>, checked: Option<bool>) -> Self {
Self {
value: Value::new(value),
checked,
Expand Down Expand Up @@ -164,7 +164,7 @@ impl VTag {
#[allow(clippy::too_many_arguments)]
pub fn __new_input(
value: Option<AttrValue>,
checked: bool,
checked: Option<bool>,
node_ref: NodeRef,
key: Option<Key>,
// at bottom for more readable macro-expanded coded
Expand Down Expand Up @@ -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<bool> {
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;
}
}

Expand Down Expand Up @@ -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);
}
}
Expand Down

0 comments on commit bb71b5d

Please sign in to comment.