dioxus icon indicating copy to clipboard operation
dioxus copied to clipboard

can't clear textarea

Open sdwoodbury opened this issue 3 years ago • 4 comments

Problem using the value attribute for an input allows for clearing the content of the input from within a callback. textarea should be able to do this too.

Steps To Reproduce

Steps to reproduce the behavior:

fn App(cx: Scope) -> Element {
    let text = use_state(&cx, String::new);

    cx.render(rsx! {
        textarea {
            value: "{text}",
            oninput: move |evt| text.set(evt.value.clone()),
            onkeypress: move |evt| {
                if evt.key_code == KeyCode::Enter  {
                    text.set(String::from(""));
                }
            },
        },
    })
}
  • input some text
  • press enter
  • the text does not disappear

Expected behavior

  • the textarea should be cleared

Questionnaire

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

sdwoodbury avatar Oct 19 '22 15:10 sdwoodbury

Oh, weird, it's the order of the two events firing. It seems like oninput gets called after onkeypress, so the value is being overwriting with the new value. I tried playing with the order of the handlers and it doesn't seem to do anything, so maybe it's how the DOM is handling the events.

I think technically you'd need to prevent default on the event... but you'd need to do it conditionally which we unfortunately don't support 100% right now (coming next version).

In the short term you can work around it.

The even weirder thing here is that the events aren't batched - IE the component is rendering twice as it handles each handler, which shouldn't be happening, so I consider this a bug with event ordering.

fn app(cx: Scope) -> Element {
    let model = use_state(&cx, || String::from("asd"));
    let clearing_state = &*cx.use_hook(|| Cell::new(false));

    cx.render(rsx! {
        textarea {
            class: "border",
            rows: "10",
            cols: "80",
            value: "{model}",
            oninput: move |e| {
                if !clearing_state.get() {
                    clearing_state.set(false);
                    model.set(e.value.clone())
                }
            },
            onkeydown: move |evt| {
                if evt.key_code == KeyCode::Enter  {
                    clearing_state.set(true);
                    model.set(String::from(""));
                }
            },
        }
    })
}

jkelleyrtp avatar Oct 19 '22 16:10 jkelleyrtp

@jkelleyrtp this is very helpful! thank you!

sdwoodbury avatar Oct 20 '22 19:10 sdwoodbury

@jkelleyrtp The problem is no longer here. Full code that is working with v0.5

#![allow(non_snake_case)]

use dioxus::prelude::*;
use log::LevelFilter;


fn main() {
    // Init debug
    dioxus_logger::init(LevelFilter::Info).expect("failed to init logger");
    console_error_panic_hook::set_once();

    launch(App);
}


fn App() -> Element {
    let mut text = use_signal(String::new);

    rsx! {
        textarea {
            value: "{text}",
            oninput: move |evt| text.set(evt.value().clone()),
            onkeypress: move |evt| {
                if evt.key() ==  Key::Enter {
                    text.set(String::from(""));
                }
            },
        },
    }
}

tkr-sh avatar Apr 06 '24 11:04 tkr-sh