npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

on-ngx-event-bus

v1.0.0

Published

Broadcast cross-system Angular events — no services, zero DI/providers, zero RxJS/signals, zero leaks, fully typed and effortless.

Readme

ngx-event-bus

CircleCI codecov SSR NPM Version npm package size License Angular Downloads

A lightweight, fully-tested, type-safe global event bus for Angular — powered by decorators, pure functions, and zero shared state.

Broadcast strongly-typed events anywhere in your app and react to them declaratively — without services, DI, providers, RxJS, Signals, or tight coupling.

⚠️ The on- prefix is used solely to avoid a naming conflict on npm and has no functional meaning.

Motivation

In many Angular applications, components that are completely unrelated still need to communicate.

When the app is not built around a state-management solution, a common approach is to introduce a shared service — usually based on RxJS Subject's or Signals — and use it as a communication bridge.

This typically requires:

  • Services, providers, and dependency injections
  • RxJS tools or Signals
  • Manual lifecycle handling to avoid memory leaks (in the case of RxJS)

ngx-event-bus takes a different approach.

It is built on native JavaScript events, automatically adds and removes event listeners to prevent memory leaks, and requires no services, no DI, and no module setup or imports. Event handling is simple, declarative, and free from shared state.

Compatibility

✅ Angular support: Angular v9 and above

Supports all Angular entities:

  • Components
  • Directives
  • Services
  • Pipes

Quick Start 🚀

Install

# npm
npm install on-ngx-event-bus

# yarn
yarn add on-ngx-event-bus

# pnpm
pnpm add on-ngx-event-bus

Usage

Broadcasting an event 🛜​

import { broadcast, GEvent } from "on-ngx-event-bus";

publish(): void {
  broadcast(
    new GEvent("MY_EVENT", {
      metadata: "My event data..."
    })
  );
}
  • The event's payload can be any type of data — primitives, objects, functions, and more. (If no payload is provided, the default is null)

Intercepting an event 📡

import { Component } from "@angular/core";
import { Interceptor, intercept } from "on-ngx-event-bus";

@Interceptor([
  { type: "MY_EVENT", action: "handleEvent" }
])
@Component({
  selector: "app-home",
  template: `Home`
})
export class HomeComponent {
  constructor() {
    intercept(this);
  }

  handleEvent(payload: { metadata: string }): void {
    console.log("Event intercepted: ", payload);
  }
}
  • ⚠️ Mandatory: Always call intercept(this) in the constructor to activate the @Interceptor.

  • The @Interceptor decorator can intercept and handle any number of events, without limits.

🎯 Targeted Events

By default, events are broadcast globally — each interceptor listening to the same event type will receive them.

However, in some scenarios you may want only specific listeners to react to an event, even if multiple interceptors are registered for the same type. To support this, events can be optionally sent with a key (string).

Broadcasting a targeted event 🛜​

publish(): void {
  broadcast(
    new GEvent("MY_EVENT", {
      metadata: "My event data..."
    }, "BUS::MY_EVENT::A9F3-77XQ") // 🔑​
  );
}

Intercepting a targeted event 📡

@Interceptor([
  { type: "MY_EVENT", action: "handleTargetedEvent", key: "BUS::MY_EVENT::A9F3-77XQ" }
])
@Component({
  selector: "app-home",
  template: `Home`
})
export class HomeComponent {
  constructor() {
    intercept(this);
  }

  handleTargetedEvent(): void {
    console.log("Will be triggered only if the key matches...");
  }
}
  • Events broadcast with a mismatched key will be rejected by the @Interceptor ❌

Advanced Usage ⚡

ngx-event-bus supports fully-typed events in 3 different levels, from quick-and-loose to fully enforced best practices.


1️⃣ Loose / Quick Usage

broadcast(new GEvent("MY_EVENT", {
  metadata: "Quick, untyped payload"
}));
  • ✅ Fast — minimal setup, just fire-and-forget.
  • ✅ Flexible — any shape of payload is allowed.
  • ❌ No type safety (developer choice)

2️⃣ Generic enforce - Strongly Typed

broadcast(
  new GEvent<"MY_EVENT", { metadata: string }>("MY_EVENT", {
    metadata: "Payload and event name are generic enforced."
  })
);

Or even smarter, with Enums/types and interfaces

enum MyEventTypes {
  MyEvent = "MY_EVENT"
}

interface MyEventPayload {
  metadata: string;
}

broadcast(
 new GEvent<MyEventTypes.MyEvent, MyEventPayload>(
   MyEventTypes.MyEvent, {
     metadata: "Payload and event name are generic enforced."
   })
);
  • ✅ Payload enforced — TypeScript ensures payload shape is correct.
  • ✅ Event names centralized — reduces typos and keeps event names consistent.
  • ✅ Better developer experience — IDE autocompletion works.
  • ❌ Event–payload relationship not fully enforced — nothing prevents using the wrong payload with a given event type.

3️⃣ Fully Enforced, Best Practice 🥇

By extending the GEvent class, you can create your own fully enforced events. This ensures both the event type and its payload are strictly typed, making your code refactor-safe and perfect for large apps.

import { GEvent, broadcast } from 'on-ngx-event-bus';

export class MyEvent extends GEvent<MyEventTypes.MyEvent, MyEventPayload> {
  static readonly TYPE = MyEventTypes.MyEvent;

  constructor(payload: MyEventPayload) {
    super(MyEvent.TYPE, payload);
  }
}

broadcast(
  new MyEvent({
    metadata: "Fully typed and refactor-safe!"
  })
);
  • ✅ Fully typed — TypeScript strictly enforces both event type and payload, guaranteeing their correct relationship.
  • ✅ Refactor-safe — renaming the event or payload interface will automatically propagate errors if used incorrectly.
  • ✅ Best developer experience — IDE autocompletion, type-checking, and maintainability are maximized.
  • ✅ Large-app ready — ideal for apps with many events and complex interactions.

Final Thoughts ✨

ngx-event-bus is designed to scale with your application — from small components to large, event-rich Angular systems.

It removes boilerplate, enforces correctness at compile time, and lets you focus on intent, not wiring. If your app relies on clean, decoupled communication, this library is built for you.

Help / Support 💬

If you run into any issues or have questions about using ngx-event-bus, feel free to reach out.

📧 Email: [email protected]

🐞 Bug reports & feature requests:
Please open an issue on GitHub