asljs-eventful
v0.4.9
Published
Lightweight event helper adding on/off/emit to any object.
Readme
eventful
Part of Alexandrite Software Library – a set of high‑quality, performant JavaScript libraries for everyday use.
Lightweight event helper adding on/off/emit to any object.
Installation
npm install asljs-eventfulNPM Package: asljs-eventful
Public Exports
The package-root export surface includes:
eventfulEventfulBaseisEventfulLikeasEventfulLikeListenerError- TypeScript types including
EventfulLike,EventName,EventMap,Eventful,EventfulFactory,EventfulOptions,Listener, andTraceFn
Usage
Special Behavior
eventful is not only an object enhancer. The package-level eventful
function also acts as a global emitter for lifecycle and error events.
If you change lifecycle, tracing, or listener-error behavior, then preserve that package-level emitter contract.
Stable Behavior
These behaviors are part of the supported contract, not just current examples:
eventfuladdson,once,off,emit,emitAsync, andhaseventfulalso acts as a package-level global emitter- strict mode propagates listener errors
- non-strict mode isolates listener failures through the configured error path
ListenerErrorprotects against recursive failures in global error handling
Preferred Patterns
- If you are enhancing a plain object, then use
eventful(target). - If you are enhancing an existing class instance and cannot change
inheritance, then call
eventful(this)in the constructor. - If you control a new class hierarchy and event support is part of the type
design, then extend
EventfulBase. - If you are writing TypeScript and want typed listener signatures, then
declare an event map and use the exported
Eventful<...>types.
Basic (JavaScript)
Adding events to an object, add listeners, and emit events:
import { eventful } from 'asljs-eventful';
const obj = eventful({ name: 'Alice' });
obj.on('greet',
msg => console.log(`${msg}, ${obj.name}!`));
// writes "Hello, Alice!" to console
obj.emit('greet', 'Hello');Basic (TypeScript)
import { eventful, type Eventful } from 'asljs-eventful';
type Events =
{ greet: [msg: string] };
const obj: { name: string } & Eventful<Events> =
eventful({ name: 'Alice' });
obj.on('greet',
msg => console.log(`${msg}, ${obj.name}!`));
// writes "Hello, Alice!" to console
obj.emit('greet', 'Hello');Inheritance (JavaScript)
Adding events to a class via inheritance:
import { EventfulBase } from 'asljs-eventful';
class MyClass extends EventfulBase {
constructor(name) {
super();
this.name = name;
}
greet() {
this.emit(
'greet',
`Hello, ${this.name}`);
}
}Inheritance (TypeScript)
import { EventfulBase } from 'asljs-eventful';
class MyClass extends EventfulBase {
name: string;
constructor(name: string) {
super();
this.name = name;
}
greet() {
this.emit(
'greet',
`Hello, ${this.name}`);
}
}Construction (JavaScript)
Adding events to an existing class during construction:
import { eventful } from 'asljs-eventful';
export class MyClass {
constructor(name) {
eventful(this);
this.name = name;
}
greet() {
this.emit(
'greet',
`Hello, ${this.name}`);
}
}Construction (TypeScript)
import { eventful, type Eventful } from 'asljs-eventful';
type MyClassEvents =
{ greet: [message: string]; };
export class MyClass implements Eventful<MyClassEvents> {
name: string;
declare on: Eventful<MyClassEvents>['on'];
declare once: Eventful<MyClassEvents>['once'];
declare off: Eventful<MyClassEvents>['off'];
declare emit: Eventful<MyClassEvents>['emit'];
declare emitAsync: Eventful<MyClassEvents>['emitAsync'];
declare has: Eventful<MyClassEvents>['has'];
constructor(name: string) {
eventful(this);
this.name = name;
}
greet() {
this.emit(
'greet',
`Hello, ${this.name}`);
}
}Advanced Options
Trace event invocations to console:
const obj =
eventful(
{ },
{ trace:
(action, payload) => {
console.log(
`Action: ${action}`,
payload);
} });
// Tracing (event, payload):
// - 'new' on creation, { object }
// - 'on' when subscribing, { object, event, listener }
// - 'off' when unsubscribing, { object, event, listener }
// - 'emit' for sync emit, { object, event, args, listeners }
// - 'emitAsync' for async emit, { object, event, args, listeners }Custom error handler for listener errors:
const obj =
eventful(
{ },
{ error:
({ error, object, event, listener }) => {
console.error(
`Error in listener for event "${event}"`,
error);
} });Strict mode to propagate listener errors:
const obj =
eventful(
{ },
{ strict: true });Global Events
eventful is also a global emitter. When you create an enhanced object via
eventful(target, options), its lifecycle and actions are traced via the
per-instance trace hook and also emitted as global events on eventful.
const offNew =
eventful.on(
'new',
({ object }) => {
console.log('created', object);
});
const offError =
eventful.on(
'error',
({ error, object, event }) => {
console.error('listener error', event, error);
});
// Later
offNew();
offError();Note: if a global eventful.on('error', ...) listener throws, eventful
throws a ListenerError (an Error subclass with fields
{ error, object, event, listener }) to avoid an infinite error loop.
API
eventful([target], [options])
Wraps the target object with event capabilities. If no target is provided,
a new empty object is created.
target(Object): The object to be enhanced with event capabilities.options(Object): Configuration options.error(Function | null): Optional error hook called with{ error, object, event, listener }.trace(Function | null): Optional trace hook called with(action, payload).strict(Boolean): If true, propagates listener errors; otherwise they are isolated. Defaults to false.
on(event, listener)
Registers a listener for the specified event.
event(String | Symbol): The event name.listener(Function): The callback function to be invoked when the event is emitted.
Returns a function to remove the listener.
once(event, listener)
Registers a one-time listener for the specified event. The listener is removed after its first invocation.
event(String | Symbol): The event name.listener(Function): The callback function to be invoked when the event is emitted.
Returns a function to remove the listener.
Example:
obj.once(
'tick',
n => console.log('first only', n));
obj.emit('tick', 1); // logs
obj.emit('tick', 2); // no-op; already unsubscribedoff(event, listener)
Removes a listener for the specified event.
event(String | Symbol): The event name.listener(Function): The callback function to be removed.
emit(event, ...args)
Emits the specified event, invoking all registered listeners with the provided arguments.
event(String | Symbol): The event name....args(Any): Arguments to pass to the listeners.
emitAsync(event, ...args)
Emits the specified event asynchronously, running listeners in parallel. In non-strict mode, all listeners run and rejections are isolated; in strict mode, the first rejection causes the returned promise to reject.
event(String | Symbol): The event name....args(Any): Arguments to pass to the listeners.
Returns a Promise that resolves when all listeners have been invoked.
has(event)
Checks if there are any listeners registered for the specified event.
event(String | Symbol): The event name.
Returns true if there are listeners, otherwise false.
Example:
const off =
obj.on('e', () => {});
console.log(obj.has('e')); // true
off();
console.log(obj.has('e')); // falseLicense
MIT License. See LICENSE for details.
Related Packages
- If you need property change tracking, see
asljs-observable. - If you need DOM binding built on observable state, see
asljs-data-binding.
