Live values
observe(element, callback, options?) calls callback(value, event) with obfo(element, options) whenever the element
sees an input, change or reset event, and returns an unsubscribe function.
import { observe } from "@johnhenry/obfo";
const stop = observe(form, (value, event) => render(value), { cast: "auto", immediate: true });// laterstop();Timing
Section titled “Timing”The call is made a task later (setTimeout(0) on the element’s window), not synchronously and not in a microtask:
- One edit, one call. A checkbox click fires
inputand thenchange, and a browser runs microtasks between the two native events, so a microtask would call back twice. A task later, both have fired. - Resets read the reset values. A
resetevent fires before the fields are reset; a task later they have been. eventis the last event seen before the call (nullfor theimmediatecall).
Options
Section titled “Options”| Option | Default | Does |
|---|---|---|
debounce |
0 |
Milliseconds to wait for a pause in events before calling back: every event restarts the wait. |
immediate |
false |
Also call back once, synchronously, with the current value. |
signal |
none | An AbortSignal that unsubscribes. An already-aborted signal never subscribes (and immediate doesn’t fire). |
onError |
none | Receives an error thrown while reading (a child with no key, a bigint cast on text). Without it the error is thrown from the timer, where the browser reports it. |
cast, container, submit, parse |
Passed to obfo. |
Unsubscribing also cancels a call that is already scheduled.
What it doesn’t hear
Section titled “What it doesn’t hear”- Property writes.
input.value = "x"orinput.checked = truefrom script fires no event. Usefill(form, value, { dispatch: true }), or dispatch aninputevent yourself. - Structure changes. Fields added or removed are read on the next event, not when they change. Call your callback
yourself (or
obfo) after changing the form’s markup, or re-observea replaced form. - Events outside the element. Listeners are on
element, so an input outside it (even one associated with the form through itsformattribute) isn’t heard, and isn’t read either.
Feeding something else
Section titled “Feeding something else”// a signalle signal that always equals the form's objectconst formValue = signal(null);observe(form, (value) => { formValue.value = value; }, { cast: "auto", immediate: true });
// a dataflow node whose dependents rerun on every editlet current;observe(form, (value) => { current = value; flow.invalidate("form"); }, { cast: "auto", immediate: true });