Skip to content

Events

EventBus is a static publish/subscribe channel for telling views that something happened: a user signed in, a list changed, a file finished uploading. All methods are static, so there is no instance to create.

import { EventBus } from "jops-core";
EventBus.subscribe(this, "user:login", (user) => this.showUser(user));
EventBus.send("user:login", { name: "Alice" });

send(event, data?) calls every subscriber of that event with the optional payload. Event names are plain strings; a "topic:action" style keeps them readable.

Inside a view, pass the view itself as the first argument. The subscription is then owned by the view and removed automatically when the view is destroyed: by removeSubView(), by the Router, or when the app is unmounted.

src/Header.js
import { View, EventBus, layout } from "jops-core";
export default class Header extends View {
constructor() {
super();
this.layout = layout`<header><span id="user"></span></header>`;
this.inflate();
}
onLayout() {
EventBus.subscribe(this, "user:login", (user) => {
this.get("user").set(layout`${user.name}`);
});
}
}

No cleanup code is needed. This is the form to use in views.

Without an owner, a subscription is global: it stays until you unsubscribe it. To be able to unsubscribe, keep a reference to the callback. An inline arrow function passed to subscribe() can never be removed.

const onLogin = (user) => console.log(user.name);
EventBus.subscribe("user:login", onLogin);
EventBus.unsubscribe("user:login", onLogin); // same function reference

Global subscriptions suit app-level code that lives as long as the page, such as a logger or a model object.

If a view does use a global subscription, remove it in one of two places:

// 1. When the view is destroyed: override destroy() and call super.destroy()
destroy() {
EventBus.unsubscribe("prices:tick", this.onTick);
super.destroy();
}
// 2. Only while the view is in front: subscribe in onResume(), unsubscribe in onPause()
onResume() {
this.onTick = (price) => this.showPrice(price);
EventBus.subscribe("prices:tick", this.onTick);
}
onPause() {
EventBus.unsubscribe("prices:tick", this.onTick);
}

The second form fits Router screens that should only react while visible. Remember that onPause() is not called when a view is destroyed, so a stacked view also needs the destroy() cleanup.

unsubscribe(event, callback) works for owned and global subscriptions alike. Two more methods cover the rest:

  • EventBus.unsubscribeAll(owner) removes every subscription of one owner (View.destroy() calls it for you).
  • EventBus.clear() removes every listener of every event.

The EventBus carries the “something changed” signal; the Store holds the data. A model object that writes to the Store and then sends an event, with views that subscribe in onLayout(), keeps every visible view up to date:

class Counter extends View {
onLayout() {
EventBus.subscribe(this, "tasks:changed", () => this.showCount());
this.showCount();
}
showCount() {
this.get("count").set(String(Tasks.all().length));
}
}