Replies: 1 comment
-
I think I've got something working: Usage: let sign_up = create_server_action::<SignUp>();
let state = sign_up.into_sync_state();
let (username, set_username) = state.sync_with(|r| r.values.username.clone(), String::new());
let (username_error, set_username_error) = state.sync_with(|r| r.errors.username, None); sync_state.rs: use leptos::*;
pub struct SyncState<T: 'static> {
response: RwSignal<Option<Result<T, ServerFnError>>>,
version: RwSignal<usize>,
}
impl<T: Clone + PartialEq> SyncState<T> {
pub fn new<A>(action: Action<A, Result<T, ServerFnError>>) -> Self {
let response = action.value();
let version = action.version();
Self { response, version }
}
pub fn sync_with<O: Clone + PartialEq + Default>(
&self,
server_value: impl 'static + Copy + FnOnce(&T) -> O,
initial_value: O,
) -> (Signal<O>, WriteSignal<O>) {
let response = self.response;
let version = self.version;
let (value, set_value) = create_signal(initial_value);
let versioned = create_memo(move |prev| {
let server_version = version.get_untracked();
let prev_server_version = prev.map(|(_, v, _)| *v).unwrap_or(0);
let prev_client_version = prev.map(|(_, _, v)| *v).unwrap_or(0);
let server_value = response.with(|v| match v {
Some(Ok(output)) => Some(server_value(output)),
_ => None,
});
let client_value = value.get();
if server_version > prev_server_version {
if let Some(server_value) = server_value {
return (server_value, server_version, prev_client_version);
}
}
(client_value, server_version, prev_client_version + 1)
});
let latest = Signal::derive(move || versioned().0);
(latest, set_value)
}
}
pub trait IntoSyncState<T> {
fn into_sync_state(self) -> SyncState<T>;
}
impl<A, T: Clone + PartialEq> IntoSyncState<T> for Action<A, Result<T, ServerFnError>> {
fn into_sync_state(self) -> SyncState<T> {
SyncState::new(self)
}
} The version juggling in the |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I'm trying to create a form that has both server-side and client-side validation & sanitization. For any field in the form:
The field's value should be the most recent of:
a. The controlled value set by the client in response to
on:change
eventsb. A field from the action value returned by the server after submitting an invalid field
The field's error message should be the most recent of:
a. The controlled value set by the client in response to
on:blur
eventsb. A field from the action value returned by the server after submitting an invalid field
The server-returned value for a field or error message should take priority until the user changes the input value again.
I can't figure out how to make this work. I've tried using
create_memo
, reacting to the server actionversion
, updating the server action value directly from event handlers (this kind of works but has other issues)The only solution that I can think of is to use a
create_effect
, but I understand that you should not usecreate_effects
to synchronize signals. Is there a better solution?Beta Was this translation helpful? Give feedback.
All reactions