Document .once() method and 'loaded' event, update npm packages
Update npm packages including @jqhtml/core 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -974,22 +974,36 @@ CREATING COMPONENTS
|
||||
|
||||
LIFECYCLE EVENT CALLBACKS
|
||||
External code can register callbacks for lifecycle events using
|
||||
the .on() method. Useful when you need to know when a component
|
||||
reaches a certain state.
|
||||
the .on() and .once() methods. Useful when you need to know when
|
||||
a component reaches a certain state.
|
||||
|
||||
Supported Events:
|
||||
'render' - Fires after render phase completes
|
||||
'create' - Fires after create phase completes
|
||||
'load' - Fires after load phase completes (data available)
|
||||
'loaded' - Fires after on_loaded() completes (this.data set and frozen)
|
||||
'ready' - Fires after ready phase completes (fully initialized)
|
||||
|
||||
Methods:
|
||||
.on(event, callback) - Register callback, fires on every occurrence
|
||||
.once(event, callback) - Register callback, fires only once
|
||||
|
||||
Both methods share the same behavior:
|
||||
- If the event already fired, callback executes immediately
|
||||
- Returns this for chaining
|
||||
- Custom events also supported (see CUSTOM COMPONENT EVENTS)
|
||||
|
||||
The difference: .on() fires on every future occurrence (useful for
|
||||
re-renders), while .once() fires at most once and then removes itself.
|
||||
|
||||
Awaiting Data in Async Methods:
|
||||
When a method needs data that may not be loaded yet, await the 'load'
|
||||
event. If the event already fired, the callback executes immediately:
|
||||
When a method needs data that may not be loaded yet, await the
|
||||
'loaded' event. If the event already fired, the callback executes
|
||||
immediately. Use .once() since you only need notification once:
|
||||
|
||||
async get_display_name() {
|
||||
// Wait for on_load() to complete if not already
|
||||
await new Promise(resolve => this.on('load', resolve));
|
||||
await new Promise(resolve => this.once('loaded', resolve));
|
||||
return `${this.data.first_name} ${this.data.last_name}`;
|
||||
}
|
||||
|
||||
@@ -1004,6 +1018,11 @@ LIFECYCLE EVENT CALLBACKS
|
||||
// Access component data, DOM, etc.
|
||||
});
|
||||
|
||||
// Fire only once (even across re-renders)
|
||||
component.once('ready', (comp) => {
|
||||
console.log('First ready!', comp);
|
||||
});
|
||||
|
||||
// Chain directly
|
||||
$('#my-component').component().on('ready', (component) => {
|
||||
console.log('User data:', component.data.user);
|
||||
@@ -1013,17 +1032,16 @@ LIFECYCLE EVENT CALLBACKS
|
||||
component
|
||||
.on('render', () => console.log('Dashboard rendered'))
|
||||
.on('create', () => console.log('Dashboard created'))
|
||||
.on('load', () => console.log('Dashboard data loaded'))
|
||||
.on('loaded', () => console.log('Dashboard data loaded'))
|
||||
.on('ready', () => console.log('Dashboard ready'));
|
||||
|
||||
Key behaviors:
|
||||
- Immediate execution: If lifecycle event already occurred,
|
||||
callback fires immediately
|
||||
- Future events: Callback also registers for future occurrences
|
||||
(useful for re-renders)
|
||||
callback fires immediately (both .on() and .once())
|
||||
- .on(): Callback persists for future occurrences (re-renders)
|
||||
- .once(): Callback fires once then auto-removes
|
||||
- Multiple callbacks: Can register multiple for same event
|
||||
- Chaining: Returns this so you can chain .on() calls
|
||||
- Custom events also supported (see CUSTOM COMPONENT EVENTS)
|
||||
- Chaining: Both return this so you can chain calls
|
||||
|
||||
Example - Wait for component initialization:
|
||||
// React when dashboard component is ready
|
||||
@@ -1031,14 +1049,12 @@ LIFECYCLE EVENT CALLBACKS
|
||||
console.log('Dashboard loaded:', this.data);
|
||||
});
|
||||
|
||||
// Process component data after load
|
||||
$('#data-grid').component().on('load', (comp) => {
|
||||
// One-time notification when data loads
|
||||
$('#data-grid').component().once('loaded', (comp) => {
|
||||
const total = comp.data.items.reduce((sum, i) => sum + i.value, 0);
|
||||
$('#total').text(total);
|
||||
});
|
||||
|
||||
Available in JQHTML v2.2.81+
|
||||
|
||||
CUSTOM COMPONENT EVENTS
|
||||
Components can fire and listen to custom events using the jqhtml event
|
||||
bus. Unlike jQuery's .trigger()/.on(), the jqhtml event bus guarantees
|
||||
@@ -1059,6 +1075,11 @@ CUSTOM COMPONENT EVENTS
|
||||
console.log('Event data:', data);
|
||||
});
|
||||
|
||||
// Listen only once
|
||||
this.sid('child_component').once('my_event', (component, data) => {
|
||||
console.log('First occurrence only');
|
||||
});
|
||||
|
||||
From external code:
|
||||
$('#element').component().on('my_event', (component, data) => {
|
||||
// Handle event
|
||||
@@ -1066,6 +1087,7 @@ CUSTOM COMPONENT EVENTS
|
||||
|
||||
Callback Signature:
|
||||
.on('event_name', (component, data) => { ... })
|
||||
.once('event_name', (component, data) => { ... })
|
||||
|
||||
- component: The component instance that fired the event
|
||||
- data: Optional data passed as second argument to trigger()
|
||||
@@ -1109,14 +1131,14 @@ EVENT HANDLER PLACEMENT
|
||||
|
||||
Where to register event handlers depends on what you're attaching to:
|
||||
|
||||
Component Events (this.on()) - Register in on_create():
|
||||
Component Events (this.on()/this.once()) - Register in on_create():
|
||||
Component events attach to this.$ which persists across re-renders.
|
||||
Register once in on_create() to avoid infinite loops.
|
||||
|
||||
on_create() {
|
||||
// Component event - register once
|
||||
this.on('file-drop', (_, data) => this._handle(data));
|
||||
this.on('custom-event', (_, data) => this._process(data));
|
||||
this.once('initialized', () => this._setup());
|
||||
}
|
||||
|
||||
DANGER: If registered in on_ready() and the handler triggers
|
||||
@@ -1146,9 +1168,9 @@ EVENT HANDLER PLACEMENT
|
||||
}
|
||||
|
||||
Summary:
|
||||
this.on('event', ...) → on_create() (component events)
|
||||
this.sid('child').on('event') → on_ready() (child component events)
|
||||
this.$sid('elem').on('click') → on_render() (child DOM events)
|
||||
this.on/once('event', ...) → on_create() (component events)
|
||||
this.sid('child').on/once('event') → on_ready() (child component events)
|
||||
this.$sid('elem').on('click') → on_render() (child DOM events)
|
||||
|
||||
$REDRAWABLE ATTRIBUTE - LIGHTWEIGHT COMPONENTS
|
||||
Convert any HTML element into a re-renderable component using the
|
||||
|
||||
@@ -222,7 +222,7 @@ BREADCRUMB SYSTEM
|
||||
// Helper to await loaded data
|
||||
async _await_loaded() {
|
||||
if (this.data.contact && this.data.contact.id) return;
|
||||
await new Promise(resolve => this.on('load', resolve));
|
||||
await new Promise(resolve => this.once('loaded', resolve));
|
||||
}
|
||||
|
||||
async page_title() {
|
||||
@@ -248,17 +248,17 @@ BREADCRUMB SYSTEM
|
||||
|
||||
Awaiting Loaded Data:
|
||||
Breadcrumb methods are called BEFORE on_load() completes. If a method
|
||||
needs loaded data (e.g., contact name), it must await the 'load' event:
|
||||
needs loaded data (e.g., contact name), it must await the 'loaded' event:
|
||||
|
||||
async _await_loaded() {
|
||||
// Check if data is already loaded
|
||||
if (this.data.contact && this.data.contact.id) return;
|
||||
// Otherwise wait for 'load' event
|
||||
await new Promise(resolve => this.on('load', resolve));
|
||||
// Otherwise wait for 'loaded' event
|
||||
await new Promise(resolve => this.once('loaded', resolve));
|
||||
}
|
||||
|
||||
The 'load' event fires immediately if already past that lifecycle
|
||||
phase, so this pattern is safe to call multiple times.
|
||||
The 'loaded' event fires after on_load() completes and this.data is
|
||||
set. Using once() is appropriate since it only needs to fire once.
|
||||
|
||||
RSX_BREADCRUMB_RESOLVER
|
||||
Framework class that handles breadcrumb resolution with caching.
|
||||
|
||||
Reference in New Issue
Block a user