Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | 1x | import { enhance } from '$app/forms';
import type { Action } from 'svelte/action';
interface AutosaveOptions {
/** Only auto-submit while this is true (e.g. an already-logged row). Defaults to always-on. */
enabled?: boolean;
}
/**
* Immediate-save as a reusable action — the "no Save button" interaction principle.
* Progressively enhances the form (`use:enhance`, so submits round-trip with no
* full reload when client JS is live) AND submits it whenever an associated field
* changes. Native Enter/submit still posts when JS is unavailable.
*
* Change listeners are attached to `form.elements` (not just the form) because
* controls associated via the `form=` attribute render outside the form's DOM
* subtree, so their `change` events never bubble to it.
*/
export const autosave: Action<HTMLFormElement, AutosaveOptions | undefined> = (form, options) => {
// `reset: false` is load-bearing, not cosmetic. The default `use:enhance`
// resets the <form> on a successful submission, which blanks every
// associated input to its (empty) defaultValue — Svelte writes the `value`
// PROPERTY, never the reset-restoring attribute. The follow-up reconciling
// `invalidateAll()` reload only re-writes an input whose reloaded value
// DIFFERS from the one Svelte last wrote (`set_value` short-circuits equal
// values), so an input left unchanged by the edit (e.g. weight when only
// reps changed) stays blank and shows the unit placeholder instead of its
// logged value. Suppressing the reset keeps the inputs showing the athlete's
// values; invalidateAll still reconciles them against the DB.
const enhancement = enhance(form, () => ({ update }) => update({ reset: false }));
let enabled = options?.enabled ?? true;
const onChange = () => {
if (enabled) form.requestSubmit();
};
const listened: Element[] = [];
for (const el of Array.from(form.elements)) {
el.addEventListener('change', onChange);
listened.push(el);
}
return {
update(next) {
enabled = next?.enabled ?? true;
},
destroy() {
for (const el of listened) el.removeEventListener('change', onChange);
enhancement?.destroy?.();
}
};
};
|