Skip to content

Commit 828fa84

Browse files
committed
Fixed timing issue with SPA,
Added workaround for load function (invalidateAll) being overwritten by form action.
1 parent 9e7b758 commit 828fa84

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

src/lib/client/superForm.ts

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -315,11 +315,6 @@ type FormDataOptions = Partial<{
315315
keepFiles: boolean;
316316
}>;
317317

318-
type FormUpdate = (
319-
result: Exclude<ActionResult, { type: 'error' }>,
320-
untaint?: boolean
321-
) => Promise<void>;
322-
323318
const formIds = new WeakMap<Page, Set<string | undefined>>();
324319
const initialForms = new WeakMap<
325320
object,
@@ -870,7 +865,7 @@ export function superForm<
870865
Errors.set(output as ValidationErrors<T>);
871866
}
872867

873-
function Form_set(data: T, options: FormDataOptions = {}) {
868+
function Form_set(data: Partial<T>, options: FormDataOptions = {}) {
874869
// Check if file fields should be kept, usually when the server returns them as undefined.
875870
// in that case remove the undefined field from the new data.
876871
if (options.keepFiles) {
@@ -886,7 +881,7 @@ export function superForm<
886881
}
887882
});
888883
}
889-
return Form.set(data, options);
884+
return Form.update(($form) => ({ ...$form, ...data }), options);
890885
}
891886

892887
function Form_shouldReset(validForm: boolean, successActionResult: boolean) {
@@ -902,7 +897,11 @@ export function superForm<
902897
if (form.valid && successResult && Form_shouldReset(form.valid, successResult)) {
903898
Form_reset({ message: form.message, posted: true });
904899
} else {
905-
rebind({ form, untaint: successResult, keepFiles: true });
900+
rebind({
901+
form,
902+
untaint: successResult,
903+
keepFiles: true
904+
});
906905
}
907906

908907
// onUpdated may check stores, so need to wait for them to update.
@@ -917,7 +916,12 @@ export function superForm<
917916
}
918917

919918
function Form_reset(
920-
opts: { message?: M; data?: Partial<T>; id?: string; posted?: boolean } = {}
919+
opts: {
920+
message?: M;
921+
data?: Partial<T>;
922+
id?: string;
923+
posted?: boolean;
924+
} = {}
921925
) {
922926
const resetData = clone(initialForm);
923927
resetData.data = { ...resetData.data, ...opts.data };
@@ -932,7 +936,7 @@ export function superForm<
932936
});
933937
}
934938

935-
const Form_updateFromActionResult: FormUpdate = async (result) => {
939+
async function Form_updateFromActionResult(result: Exclude<ActionResult, { type: 'error' }>) {
936940
if (result.type == ('error' as string)) {
937941
throw new SuperFormError(
938942
`ActionResult of type "${result.type}" cannot be passed to update function.`
@@ -964,7 +968,7 @@ export function superForm<
964968
result.status >= 200 && result.status < 300
965969
);
966970
}
967-
};
971+
}
968972

969973
//#endregion
970974

@@ -1188,25 +1192,39 @@ export function superForm<
11881192
// tainted dialog when a form doesn't use it or the browser doesn't use JS.
11891193
options.taintedMessage = undefined;
11901194

1191-
// Role rebinding
1192-
function rebind(opts: {
1195+
function rebindPage(opts: {
11931196
form: SuperValidated<T, M, In>;
11941197
untaint: TaintedFields<T> | boolean;
1195-
message?: M;
11961198
keepFiles?: boolean;
1197-
posted?: boolean;
11981199
}) {
1199-
//console.log('🚀 ~ file: superForm.ts:721 ~ rebind ~ form:', form.data); //debug
12001200
const form = opts.form;
1201-
const message = opts.message ?? form.message;
12021201

12031202
if (opts.untaint) {
12041203
Tainted_set(typeof opts.untaint === 'boolean' ? undefined : opts.untaint, form.data);
12051204
}
12061205

12071206
// Form data is not tainted when rebinding.
12081207
// Prevents object errors from being revalidated after rebind.
1208+
// Check if form was invalidated (usually with options.invalidateAll) to prevent data from being
1209+
// overwritten by the load function data
12091210
Form_set(form.data, { taint: 'ignore', keepFiles: opts.keepFiles });
1211+
}
1212+
1213+
// Role rebinding
1214+
function rebind(opts: {
1215+
form: SuperValidated<T, M, In>;
1216+
untaint: TaintedFields<T> | boolean;
1217+
message?: M;
1218+
keepFiles?: boolean;
1219+
posted?: boolean;
1220+
}) {
1221+
//console.log('🚀 ~ file: superForm.ts:721 ~ rebind ~ form:', form.data); //debug
1222+
1223+
rebindPage({ ...opts });
1224+
1225+
const form = opts.form;
1226+
const message = opts.message ?? form.message;
1227+
12101228
Message.set(message);
12111229
Errors.set(form.errors);
12121230
FormId.set(form.id);
@@ -1283,13 +1301,6 @@ export function superForm<
12831301
// Need to subscribe to catch page invalidation.
12841302
Unsubscriptions_add(
12851303
page.subscribe(async (pageUpdate) => {
1286-
// Strange timing issue in SPA mode forces a wait here,
1287-
// otherwise errors will appear even if the form is valid
1288-
// when pressing enter to submit the form (not when clicking a submit button!)
1289-
if (options.SPA) {
1290-
await new Promise((r) => setTimeout(r, 0));
1291-
}
1292-
12931304
const successResult = pageUpdate.status >= 200 && pageUpdate.status < 300;
12941305

12951306
if (options.applyAction && pageUpdate.form && typeof pageUpdate.form === 'object') {
@@ -1830,7 +1841,7 @@ export function superForm<
18301841
// This will trigger the page subscription in superForm,
18311842
// which will in turn call Data_update.
18321843
await applyAction(result);
1833-
} else if (result.type !== 'success' || !options.invalidateAll) {
1844+
} else {
18341845
// Call Data_update directly to trigger events
18351846
await Form_updateFromActionResult(result);
18361847
}

0 commit comments

Comments
 (0)