*eager
Summary
*eager is an optional modifier for *input / n-input that makes Sercrod re-render the host “eagerly” on every input-like event for text fields and textareas.
- Without
*eager, data is still written on every event, but the host only performs a narrower update (typically propagating changes to child Sercrod components). - With
*eager, the host callsupdate()after each input event on the control (subject to*stageand host-level*lazy). *eagerhas an aliasn-eager.
*eager only has effect on elements that also carry *input or n-input and are treated as text-like controls by Sercrod.
Basic example
Enable eager updates on a text input:
<serc-rod id="profile" data='{"user":{"name":""}}'>
<form>
<label>
Name:
<input type="text" *input="user.name" *eager>
</label>
<p>Preview: <span *print="user.name"></span></p>
</form>
</serc-rod>
Behavior:
- Every keystroke in the input writes to
user.name. - Because of
*eager, Sercrod callsupdate()for the host after each input event. - The
<span *print="user.name">is kept in sync keystroke-by-keystroke, without waiting for a change or submit event.
Behavior
Scope of *eager:
*eageris interpreted only when the element also has*inputorn-input.- It is a non-structural modifier: it does not change how templates are expanded, only when and how the host re-renders in response to user input.
Targeted controls:
-
When the host binds a form control through
*input/n-input, it distinguishes three main groups:-
Text-like controls:
<input>with a type that is notcheckboxorradio.<textarea>.- These use the
inputevent for “live” updates.
-
Change-driven controls:
<input type="checkbox">.<input type="radio">.<select>(single or multiple).- These use the
changeevent.
-
Everything else:
- Treated as change-driven; bound on
change.
- Treated as change-driven; bound on
-
Effects of *eager:
-
For text-like controls (text inputs and textareas):
- Every input event:
-
Writes the new value to the bound data path (via
*input). -
If the host is not staged (
*stageis not active):- If
*eager(orn-eager) is truthy:- The host calls
update()immediately.
- The host calls
- Otherwise:
- The host triggers only child updates through
_updateChildren(...).
- The host triggers only child updates through
- If
-
- Every input event:
-
For change-driven controls (checkbox, radio, select, other):
*eageris currently not consulted.- These controls always write on
change, and the update strategy is governed by*lazy(not by*eager).
In other words:
*eagerspecifically upgrades the update policy for text-like*inputbindings.- It does not override the change-event logic of checkboxes, radios, or selects.
Activation and value semantics
*eager and n-eager are treated as boolean or conditionally-boolean attributes with a small amount of convenience logic.
Recognized forms:
-
Bare attribute (always enabled):
<input *input="form.name" *eager> <input *input="form.email" n-eager>- If
*eager/n-eageris present and its attribute value is empty ornull,isEagerbecomestrue.
- If
-
Conditional expression:
<input *input="form.name" *eager="settings.livePreview"> <input *input="form.email" n-eager="user.prefersEagerInputs">- Sercrod evaluates the attribute value as a normal expression in the current scope.
- If evaluation succeeds:
isEagerisBoolean(result).
- If evaluation throws (for example, due to a
ReferenceError):- Sercrod falls back to a string-based rule:
- If the raw attribute value is
"false"(any case),isEagerisfalse. - Any other non-empty literal string makes
isEagertrue.
- If the raw attribute value is
- Sercrod falls back to a string-based rule:
Practical interpretation:
- Use bare
*eagerwhen you always want eager behavior. - Use
*eager="expr"when you want to toggle eager behavior from application data. - If you accidentally give it a literal string that is not a valid expression,
"false"disables eagerness, everything else enables it.
Interaction with *input / n-input
*eager has no meaning by itself. It only matters in combination with *input or n-input:
-
Without
*input/n-input:*eageris effectively ignored.- Sercrod does not attach eager behavior to arbitrary elements.
-
With
*input/n-input:- Sercrod reads
*eager/n-eagerduring binding setup for that control. *eagerinfluences how often the host re-renders in response to that control’s user events.
- Sercrod reads
Data writes:
-
Regardless of
*eager, when the control’s event handler fires:- Sercrod always writes the new value to the bound path via
assign_expr. *eagerdoes not delay or batch the write; it only changes the re-render strategy.
- Sercrod always writes the new value to the bound path via
Summary:
*inputcontrols “what gets written and where”.*eagercontrols “how aggressively the host re-renders after a text input changes”.
Interaction with *lazy
There are two separate uses of *lazy in Sercrod:
-
Host-level
*lazyon<serc-rod>:- Affects how often the host re-renders in response to generic updates and events.
-
Input-level
*lazyon controls that also have*input/n-input:- Affects how change-driven controls (checkbox, radio, select, other) update the host after writes.
*eager interacts only with the first group (text-like *input bindings) and does not override the second:
-
For text inputs and textareas:
*eagerdecides whether to callupdate()on each input event.- Host-level
*lazycan still influence whatupdate()actually does:- If the host is marked
*lazy, anupdate()triggered by*eagermay short-circuit to “child-only updates plus hooks” instead of a full template rebuild.
- If the host is marked
-
For change-driven controls:
*eageris ignored.*lazyon the control (or on the host) controls whetherupdate()is called on change, or whether only children are updated.
Rule of thumb:
- Use
*eageron text-like*inputcontrols when you want immediate visual feedback. - Use
*lazyon hosts or change-driven controls when you want to avoid full host re-renders on every change.
Interaction with *stage
*eager respects *stage:
-
When the host is in staged mode (
*stageis active and_stageis set):- Input handlers still write into the staged data copy.
- However, the eager update path is disabled:
- The guards around
update()check!this._stagebefore re-rendering.
- The guards around
- The host is not re-rendered on each input, even if
*eageris true.
-
When you later apply the staged changes (for example via
*applyor the appropriate host-level flow):- The host re-renders based on the staged data being committed.
*eagerdoes not affect this commit-time re-render; it only affects live updates while the host is not staged.
This allows you to combine:
*stagefor “edit, then apply” flows, with*eagerfor immediate feedback in non-staged contexts.
Evaluation timing
The value of *eager is determined when Sercrod binds the element:
- During
_renderElement, when a node with*input/n-inputis processed:- Sercrod parses and evaluates the
*eager/n-eagerattribute. - The resulting boolean
isEageris captured in the event handlers.
- Sercrod parses and evaluates the
Consequences:
- Changes to the expression behind
*eageronly take effect after the host re-renders and the binding is re-established. *eageris not re-evaluated on every keystroke; it is per-render, not per-event.
If you need to switch between eager and non-eager modes at runtime:
- Drive the condition in
*eager="..."from reactive data. - Cause a host re-render (for example by updating any data that affects the template).
- The next binding pass will pick up the new value of
*eager.
Execution model
For a text-like input with *input and optional *eager, the flow is:
-
Binding setup (render time):
- Sercrod reads the
*input/n-inputexpression and figures out a target data object. - It evaluates
*eager/n-eageronce to computeisEager. - It sets the initial control value based on the current data.
- It attaches event listeners (
inputand/orchange) that captureisEager.
- Sercrod reads the
-
On each
inputevent (text inputs and textareas):- Sercrod transforms the raw value using any installed input filters.
- It writes the value to the bound data path with
assign_expr. - If the host is not staged:
- If
isEageristrue:- It calls
update()on the host.
- It calls
- Otherwise:
- It only propagates updates to child Sercrod instances (
_updateChildren(...)).
- It only propagates updates to child Sercrod instances (
- If
-
On
changeevents (checkbox/radio/select/others):- Sercrod computes and writes the new value, similar to text inputs.
isEageris ignored; the actual update policy is controlled by*lazy.
In all cases, *eager does not change what is written, only when and how broadly the host re-renders.
Best practices
-
Use
*eagerfor “live preview” fields:- Examples: search boxes, “slug” fields, inline previews, character counters.
- These benefit from the host re-rendering on every keystroke.
-
Avoid
*eageron very heavy components:- If the host template is large or expensive to render, eager updates on every keystroke can become costly.
- Consider:
- Leaving the host in the default behavior (child-only updates).
- Or using a staged / debounced pattern at the application level.
-
Combine with
*stagefor complex forms:- Use
*stageto isolate edits. - Use
*eageronly on selected inputs where live feedback is clearly worth the cost. - Remember that
*eageris ignored while the host is staged; the main benefit appears once the host returns to non-staged mode.
- Use
-
Keep
*eagerexpressions simple:- Prefer boolean or simple property checks, such as
*eager="settings.eagerInputs". - If you need more elaborate logic, compute it in data or methods, and reference it from
*eager.
- Prefer boolean or simple property checks, such as
-
Do not rely on
*eagerfor change-only controls:- For checkboxes, radios, and selects,
*eagerdoes not alter the re-render policy in the current implementation. - For those controls, use
*lazy(or host-level*lazy) to adjust behavior.
- For checkboxes, radios, and selects,
Examples
Live search box:
<serc-rod id="search" data='{"query":"","results":[]}'>
<div>
<input
type="search"
placeholder="Type to search"
*input="query"
*eager>
</div>
<ul *each="item of results">
<li *print="item.label"></li>
</ul>
</serc-rod>
- Each keystroke updates
queryand triggersupdate()because of*eager. - A separate mechanism (for example
*postor*apiwired toquery) can refreshresults.
Conditional eager mode:
<serc-rod id="settings" data='{
"user": { "name": "" },
"ui": { "eagerPreview": true }
}'>
<label>
<input type="checkbox" *input="ui.eagerPreview">
Enable eager preview
</label>
<label>
Name:
<input
type="text"
*input="user.name"
*eager="ui.eagerPreview">
</label>
<p>Preview: <span *print="user.name"></span></p>
</serc-rod>
- When
ui.eagerPreviewistrue, name changes re-render the host on each keystroke. - When it is
false, the host falls back to the default, narrower update behavior.
Notes
*eagerandn-eagerare aliases; choose one naming style and stick to it for consistency.*eageris meaningful only in combination with*input/n-input; on other elements, it is effectively ignored.- In the current implementation:
- Text-like controls with
*inputalways write data on eachinputevent;*eagercontrols whether the host re-renders fully on each event. - Change-driven controls (checkbox, radio, select, others) do not consult
*eagerand instead rely on*lazy.
- Text-like controls with
- Host-level
*lazyand*stageare still respected;*eagercan request eager host updates, but the host’s own lazy and staged policies can limit when full re-renders actually occur.