Now.js Framework Documentation
data-on-load
data-on-load
Overview
data-on-load calls a global function after API-driven or binding-driven content is ready (similar concept to data-script, but different lifecycle). It runs on the element that declares the attribute and is intended ONLY for initialization that should happen after a payload has been inserted into the DOM. Typical callers are ApiComponent, FormManager, TableManager, and FormManager's declarative submit-result binding.
The function receives the TemplateManager context object as the second argument. In practice:
- Use
context.statefor the full normalized payload. - Use
context.datafor the primary dataset when available. - For declarative form result binding,
context.statecontains the canonical schema andcontext.datausually contains the row array used bydata-for="item in data".
Use it to:
- Run per-section initialization after an API or form payload has been inserted into a container
- Attach behavior that depends on the loaded data (e.g., populate maps, charts, third-party widgets)
- Use the signature
(element, context)wherecontext.stateis the full payload andcontext.datais the primary dataset when available
Basic Usage
<main>
<section data-on-load="initFormLoad">
<h2 data-text="data.title"></h2>
</section>
</main>function initFormLoad(element, context) {
// element: DOM element with data-on-load
// context.state: full payload
// context.data: primary dataset when available
console.log('Init section', element, context.state, context.data);
// Optional cleanup
return () => {
console.log('Cleanup section');
};
}How it runs
- ApiComponent: After rendering API data (or serving from cache),
ApiComponentwill run all[data-on-load]inside the component using the render context. - FormManager: When form data is loaded or when a successful AJAX submit re-binds a result target,
FormManagerwill run[data-on-load]using the render context. - TableManager: When a table loads data from an API and renders its rows,
TableManagerwill invoke[data-on-load]on the table element itself once after the render completes.
Note: TemplateManager/process lifecycle changed slightly in later framework versions — data-on-load is primarily intended for API-driven payloads, but FormManager will also invoke data-on-load after form initialization when there is no explicit data-load-api (for example when a form is inserted into a modal via the ResponseHandler). In that case FormManager passes a normalized payload (it prefers window._currentModalData when available, otherwise the current form values) so handlers can initialize behavior for modal or pre-rendered forms.
To avoid duplicate invocations, FormManager sets an internal flag when it has invoked data-on-load for a given form instance. If the form later receives an API payload (via data-load-api), the API-driven invocation will still run but duplicate calls are prevented by the FormManager flag.
Note: data-on-load is for API-driven loads only. For page-level initialization triggered by navigation, use data-script (RouterManager invokes data-script during navigation). The two hooks are separate and should not be interchanged.
Body-level usage (AppConfigManager)
When data-on-load is placed on the page <body> (for example to run logic after a combined config load), AppConfigManager executes that attribute and the function signature differs from the per-element handlers:
- Normal per-element usage: handlers are called as
window[fn](element, context)— signature(element, context)as described above. - Body-level usage (AppConfigManager): the attribute is compiled to a function and invoked as
fn(site, theme, config)— wheresiteis the site metadata object,themeis the current theme string, andconfigis the full config object containing site, theme and applied variables.
Example:
<body data-on-load="document.title = site.title; initHeader(site, theme, config)">
<!-- available: site, theme, config -->
</body>See the AppConfigManager documentation (docs/en/AppConfigManager.md) for more details and examples of using body-level data-on-load.
Function Signature
function initFn(element, context) {
// element: HTMLElement with data-on-load
// context.state: full TemplateManager payload
// context.data: primary dataset when available
// return optional cleanup function
}| Parameter | Type | Description |
|---|---|---|
element |
HTMLElement | Element bearing data-on-load |
context |
Object | TemplateManager context. Prefer context.state for the full payload and context.data for the primary dataset |
| Return | Effect |
|---|---|
undefined |
No cleanup |
Function |
Called on cleanup (component/form teardown) |
Tips
- Prefer
data-on-loadfor multiple independent areas; keepdata-scriptfor single entry-point logic. - If the goal is to derive display data from current form values, prefer FormManager watched API binding (
data-watch-api) so the response can be rebound through normal directives without custom JavaScript. - Keep functions idempotent—reruns can happen after re-render.
- Use returned cleanup to remove listeners/timers.
Example with declarative search results
<section id="results" data-on-load="initResults">
<div data-for="item in data">
<template>
<article data-text="item.name"></article>
</template>
</div>
</section>function initResults(element, context) {
const rows = Array.isArray(context.data) ? context.data : [];
const meta = context.state?.meta || {};
console.log('Loaded rows:', rows.length, 'page:', meta.page);
}