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
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
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