Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input field with name "value" or buttons without "type" break the app in conditional rendering #1477

Closed
1 of 3 tasks
acomanescu opened this issue Sep 20, 2023 · 6 comments
Closed
1 of 3 tasks
Assignees
Labels
bug Something isn't working desktop Suggestions related to the desktop renderer

Comments

@acomanescu
Copy link

Problem

I'm running a desktop app using dx serve on a MacOS. When I conditionally render a form that contains a field with name equals to "value", after clicking "Send" the application panics.

I noticed another bug in forms. If I have a button with no type attribute, after clicking "Send" the application removes every component. Looks like it does a form submission. Here is the snippet:

Steps To Reproduce

Panics after clicking "Send":

use dioxus::prelude::*;
use dioxus_desktop::Config;

fn main() {
    dioxus_desktop::launch_cfg(App, Config::new());
}

#[component]
fn App(cx: Scope) -> Element {
    let show_form = use_state(cx, || false);

    cx.render(
        rsx! {
            if !show_form.get() {
                rsx! {
                  button {
                      onclick: move |_| {
                          show_form.set(true);
                      },
                      "Show Form"
                  }
              }
            } else {
                rsx! {
                    form {
                        prevent_default: true,
                        onsubmit: move |_| {
                            show_form.set(false); 
                        },
                        div {
                            input { name: "value" }
                        }
                        div {
                            button {
                                r#type: "submit",
                                "Send"
                            }
                        }
                    }
              }
            }
        }
    )
}

Removes everything after clicking "Send":

use dioxus::prelude::*;
use dioxus_desktop::Config;

fn main() {
    dioxus_desktop::launch_cfg(App, Config::new());
}

#[component]
fn App(cx: Scope) -> Element {
    let show_form = use_state(cx, || false);

    cx.render(
        rsx! {
            if !show_form.get() {
                rsx! {
                  button {
                      onclick: move |_| {
                          show_form.set(true);
                      },
                      "Show Form"
                  }
              }
            } else {
                rsx! {
                    form {
                        prevent_default: true,
                        div {
                            input { name: "value" }
                        }
                        div {
                            button {
                                onclick: move |_| {
                                    show_form.set(false); 
                                },
                                "Send"
                            }
                        }
                    }
              }
            }
        }
    )
}

Expected behavior

I expect in both cases the form to hide.

Environment:

  • Dioxus version: master
  • Rust version: 1.72.0
  • OS info: MacOS
  • App platform: desktop

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
  • I don't have time to fix this right now, but maybe later
@ealmloff ealmloff added bug Something isn't working desktop Suggestions related to the desktop renderer labels Sep 20, 2023
@ealmloff
Copy link
Member

For the first error:

If you are interested in fixing this, the error looks like it is coming from here when the desktop event is deserialized from json. Specifically, the value field in the json is an empty {}, when it should be a string.

This means that the event was serialized wrong in the interpreter here or here.

For the second error:

This static HTML also reloads the page if you click the button:

<!DOCTYPE html>
<html>
<body>

<h1>The button form attribute</h1>

<form action="/action_page.php" method="get" id="nameform">
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname"><br><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname">
  <button>Submit</button>
</form>

<p>The button below is outside the form element, but still part of the form.</p>

</body>
</html>

The default type of a button is submit. If you would like to not submit, you can set the type of the button to "button":

<!DOCTYPE html>
<html>
<body>

<h1>The button form attribute</h1>

<form action="/action_page.php" method="get" id="nameform">
  <label for="fname">First name:</label>
  <input type="text" id="fname" name="fname"><br><br>
  <label for="lname">Last name:</label>
  <input type="text" id="lname" name="lname">
  <button type="button">Submit</button>
</form>

<p>The button below is outside the form element, but still part of the form.</p>

</body>
</html>

@acomanescu
Copy link
Author

Hi @ealmloff Adding prevent_default: true, to the form tag (as I have in the snippet), shouldn't prevent this behaviour?

@ealmloff
Copy link
Member

ealmloff commented Sep 20, 2023

Hi @ealmloff Adding prevent_default: true, to the form tag (as I have in the snippet), shouldn't prevent this behaviour?

prevent_default only applies to elements that have an event listener with the same type as the event you are preventing on them. It also accepts a string for the type of event to prevent default on. We would like to remove prevent default and add a prevent_default method to the event object to make this more clear, but synchronously preventing events across the wry boundary is difficult.

form {
    onsubmit: |evt| evt.prevent_default()
}

@acomanescu
Copy link
Author

@ealmloff Great explanation! So the suggestion of Jonathan would be to create some sort of React Synthetic Events.

@ealmloff
Copy link
Member

ealmloff commented Sep 20, 2023

@ealmloff Great explanation! So the suggestion of Jonathan would be to create some sort of React Synthetic Events.

Kind of, we already have synthetic events (becoming a bit less synthetic with #1402). You can stop a synthetic event from bubbling with stop_propagation, but you cannot prevent the browser behavior with a function.

The issue here is that all communication with wry (the webview library that Dioxus uses) is asynchronous. We need to create a synchronous way to run the rust code that was triggered because of the event and then potentially cancel the browser's event before it continues bubbling to other elements

@jkelleyrtp jkelleyrtp added this to the 0.5.0: Signals milestone Feb 23, 2024
@jkelleyrtp jkelleyrtp self-assigned this Mar 6, 2024
@jkelleyrtp
Copy link
Member

This is fixed! By #1974

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working desktop Suggestions related to the desktop renderer
Projects
None yet
Development

No branches or pull requests

3 participants