Skip to content

onEvent

Created by

A small utility for listening to events on any EventTarget with automatic cleanup when the current Angular lifecycle scope is destroyed (via DestroyRef.onDestroy). It uses an AbortController and passes its signal to addEventListener, so aborting removes the listener without needing removeEventListener.

Listen to an event and auto-cleanup on destroy (when called inside an injection context):

import { onEvent } from 'ngxtension/on-event';
onEvent(window, 'resize', (event) => {
console.log('Window resized', event);
});

Stop listening manually (e.g., after the first “meaningful” event):

onEvent(document, 'scroll', (event, abort) => {
if (window.scrollY > 500) {
console.log('User scrolled past 500px');
abort(); // removes the listener immediately
}
});

You can control the listener from outside the callback using the returned object. This is useful for UI feedback based on the listener’s state.

const { destroy, active } = onEvent(window, 'mousemove', (e) => {
// heavy logic
});
// Check if we are currently listening (returns Signal<boolean>)
console.log(active()); // true
// Stop listening from outside
destroy();
console.log(active()); // false
type OnEventOptions = {
once?: boolean;
capture?: boolean;
passive?: boolean;
};
  • once: Uses the native addEventListener({ once: true }) behavior (listener runs once and is then removed).
  • capture: A boolean indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.
  • passive: A boolean which, if true, indicates that the function specified by listener will never call preventDefault().
  • destroyRef: Provide a DestroyRef explicitly (useful outside injection context, or when you want a specific lifecycle scope).
  • injector: Provide an Injector explicitly so the utility can resolve DestroyRef from it when you’re not in a direct injection context.

If you call onEvent() somewhere without an active injection context (for example, inside a plain function that isn’t run via Angular DI), pass either:

  • options.destroyRef, or
  • options.injector.

If no DestroyRef can be determined, a warning will be logged in DevMode, and the listener will not be automatically cleaned up (you must call destroy manually).

export type OnEventResult = {
destroy: () => void;
active: Signal<boolean>;
}
onEvent(target: EventTarget, eventKey: string, listener: (event: Event, abort: () => void) => void, options?: OnEventOptions): OnEventResult;
  • target: The DOM element or EventTarget (e.g., window, document, ElementRef.nativeElement).
  • eventKey: The name of the event (e.g., 'click', 'scroll').
  • listener: The callback function. Receives:
    • event: The dispatched event (typed via GlobalEventHandlersEventMap when possible).
    • abort(): Call to stop listening immediately.
  • options: Configuration object for event behavior and dependency injection.

Returns an OnEventResult object:

  • destroy: A function to remove the event listener manually.
  • active: A generic Angular Signal<boolean> indicating whether the listener is currently attached.