-
I have a component that basically wraps an input with an #[component]
pub fn MultiplyBy100Input(
/// Value of a field that's a division of 100 of the users' input.
value: Field<f64>,
) -> impl IntoView {
view! {
<input
type="number"
prop:value=Signal::derive(move || value.get() * 100.0)
on:input:target=move |ev| {
if let Ok(new_value) = ev.target().value().parse::<f64>() {
// TODO: the value changes should be propagated to everywhere the field is used, except to the `value=Signal..` on this input..
value.set(new_value / 100.0);
}
}
/>
}
} This seems to work until you try to type in a value with a |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
From the point of view of the reactive system or the renderer there's no "internal" and "external" here -- the fact that you're setting the value in a callback on an element, and eventually using a derived signal that reads from that value, are independent of one another. I guess there are a few approaches:
Any of these could work, there just isn't a general solution to this specific problem. |
Beta Was this translation helpful? Give feedback.
-
Thanks @gbj, these are all great solutions. To scratch my itch, I've figured out a somewhat inelegant solution that seems to work fine: /// Wrap a field with a signal that's only updated when the field is updated from an external source and a set function to do that.
pub fn one_way_field_update<T>(field: Field<T>) -> (ReadSignal<T>, impl Fn(T) + Copy + 'static)
where
T: Clone + Send + Sync + 'static,
{
// Whether the value is updated internally or externally
let is_internal_update = StoredValue::new(false);
// Internal shadow copy of the external value
let (external_only, set_external_only) = signal(field.get_untracked());
// Update the internal value when the external one changes
let _ = Effect::watch(
move || field.get(),
move |new_value: &T, _, _| {
if !is_internal_update.get_value() {
set_external_only.set(new_value.clone());
} else {
is_internal_update.set_value(false);
}
},
false,
);
// Update the value internally, only propagating changes to the external value
let update_internal = move |new_value: T| {
is_internal_update.set_value(true);
field.set(new_value);
};
(external_only, update_internal)
} Which can be used like this: #[component]
pub fn MultiplyBy100Input(
/// Value of a field that's a division of 100 of the users' input.
value: Field<f64>,
) -> impl IntoView {
let (external_only, update_internal) = one_way_field_update(value);
view! {
<input
type="number"
prop:value=Signal::derive(move || external_only.get() * 100.0)
on:input:target=move |ev| {
if let Ok(new_value) = ev.target().value().parse::<f64>() {
update_internal(new_value / 100.0);
}
}
/>
}
} |
Beta Was this translation helpful? Give feedback.
Thanks @gbj, these are all great solutions.
To scratch my itch, I've figured out a somewhat inelegant solution that seems to work fine: