-
I'm trying to write a simple calculator in Dioxus. The documentation uses a horribly confusing example, and it doesn't show how to accept user input from standard input fields. I posed a few questions inside the closure of my I wish there were a simpler example that I could draw from, that answers these basic questions. Here's my state struct: #[derive(Copy, Debug, Clone)]
struct CalcState {
num1: i64,
num2: i64,
result: i64,
} And here's my app: fn App(cx: Scope) -> Element {
let first_name = "Trevor";
use_shared_state_provider(cx, || CalcState{num1: 0, num2: 0, result: 0});
cx.render(rsx! {
Calculator {
}
})
} And here's my Calculator component, the important bit: fn Calculator(cx: Scope) -> Element {
let calc_state = use_shared_state::<CalcState>(cx).unwrap();
render! {
div {
input {
onkeyup: |e| {
println!("{:#?}", e);
// 🚨 How do I get a reference to the "num1" input box?
// 🚨 How do I READ the value of "this" input box?
// 🚨 How do I update the calc_state variable with the new value for the "num1" field?
},
id: "num1",
value: calc_state.read().num1,
"Number 1: "
}
input {
id: "num2",
"Number 2: "
}
button {
onclick: move |event| {
println!("Clicked");
},
border: "None",
"Add"
}
label {
format!("Result: {}", calc_state.read().result)
}
}
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
As you can see, I used the IF you wish to simplify this process, consider making your own, "upgraded", input component. fn Calculator(cx: Scope) -> Element {
let calc_state = use_shared_state::<CalcState>(cx).unwrap();
let error_message = use_state(cx, || "".to_string());
render! {
div {
pre {
color: "red",
"{error_message}"
}
input {
oninput: |e| {
let value = e.value.to_owned();
if let Ok(new_num) = value.parse::<i64>() {
calc_state.write().num1 = new_num;
error_message.set("".to_string());
} else if value.is_empty() {
calc_state.write().num1 = 0;
error_message.set("".to_string());
} else {
error_message.set(format!("Invalid input: {value}"));
}
},
id: "num1",
value: "{calc_state.read().num1}",
"Number 1: "
}
input {
oninput: |e| {
let value = e.value.to_owned();
if let Ok(new_num) = value.parse::<i64>() {
calc_state.write().num2 = new_num;
error_message.set("".to_string());
} else if value.is_empty() {
calc_state.write().num1 = 0;
error_message.set("".to_string());
} else {
error_message.set(format!("Invalid input: {value}"));
}
},
id: "num2",
value: "{calc_state.read().num2}",
"Number 2: "
}
button {
onclick: move |_| {
let num1 = calc_state.read().num1;
let num2 = calc_state.read().num2;
calc_state.write().result = num1 + num2;
},
border: "None",
"Add"
}
label {
format!("Result: {}", calc_state.read().result)
}
}
}
} |
Beta Was this translation helpful? Give feedback.
As you can see, I used the
oninput
event instead ofonkeyup
, sinceoninput
is an event that gives you the new value of the input. You might also be interested in the User Input chapter of the docs. It describes an alternative to handling input within each input element, instead delegating all work to theform.onsubmit
event. Of course, you would also need to create aform
element. However, then the input validation (which I've added for your convenience), would only work once the form is submitted, and not instantly when the input is entered.IF you wish to simplify this process, consider making your own, "upgraded", input component.