dioxus icon indicating copy to clipboard operation
dioxus copied to clipboard

Checkbox inputs sometimes ignore value of `checked` attribute

Open Houndie opened this issue 1 year ago • 1 comments

Problem

I'm trying to make a controlled checkbox, and I can't always seem to control the value of the input element with the checked attribute.

Steps To Reproduce

Here's an extremely contrived but fairly minimum reproducer:

#![allow(non_snake_case)]
use dioxus::prelude::*;
use log::LevelFilter;

fn main() {
    dioxus_web::launch(App);
    dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
}

fn App(cx: Scope) -> Element {
    let is_checked = use_state(cx, || false);
    log::info!("{}", is_checked.get());
    cx.render(rsx! {
        input {
            r#type: "checkbox",
            checked: *is_checked.get(),
            onclick: |_| is_checked.set(true),
        }
        button {
            onclick: move |_| is_checked.set(!is_checked),
            "toggle checked",
        }
  })
}
   

run this with dx serve.

Expected behavior

You should see a checkbox and a button. Clicking the checkbox should always make the checkbox checked, clicking the button should toggle the state of the checkbox. In practice, the checkbox state is initialized to the value of is_checked on it's initial mount, but is then toggled on click regardless of the value of is_checked. However, the button will correctly update the checkbox to the value of is_checked.

Adding the prevent_default: "onclick" attribute to the input element will prevent any visual changes from happening to the checkbox when clicked...clicking a checked checkbox remains checked, clicking an unchecked checkbox remains unchecked. The button still correctly resets the state correctly.

Environment:

  • Dioxus version: 0.4.3
  • Rust version: 1.75.0
  • OS info: Linux
  • App platform: web

Questionnaire

  • [ ] I'm interested in fixing this myself but don't know where to start
  • [ ] I would like to fix and I have a solution
  • [x] I don't have time to fix this right now, but maybe later

Houndie avatar Jan 13 '24 15:01 Houndie

While the input type is radio instead of a checkbox, the following code meets your expectations:

fn App(cx: Scope) -> Element {
    let is_checked = use_state(cx, || false);
    render! {
          input {
              r#type: "radio",
              checked: *is_checked.get(),
              onclick: move |_| {
                is_checked.set(true);
              }
          }
          button {
              onclick: move |_| is_checked.set(!is_checked),
              "toggle checked",
          }
    }
}

amitbashan avatar Jan 15 '24 12:01 amitbashan

SolidJS has a similar behavior - attempting to control a checkbox like this does not fit with the one-way dataflow paradigm we encourage. In Dioxus we force a re-render since we don't compare values with set, but the bugged behavior remains.

I don't think we can fix this without special casing "checked" checks.

https://playground.solidjs.com/anonymous/2dec7f19-bae4-4d02-ab3c-6f606a577622

jkelleyrtp avatar Mar 07 '24 00:03 jkelleyrtp