Now.js Framework Documentation

Now.js Framework Documentation

EventManager

EN 15 Dec 2025 08:26

EventManager

Overview

EventManager is the central event bus in Now.js Framework for component communication.

When to use:

  • Need component-to-component communication
  • Need to decouple components
  • Need global event handling
  • Need pub/sub pattern

Why use it:

  • ✅ Global event bus
  • ✅ Once listeners
  • ✅ Namespaced events
  • ✅ Automatic cleanup
  • ✅ Event debugging

Basic Usage

Emit Event

EventManager.emit('user:login', { user: userData });

Listen to Event

EventManager.on('user:login', (data) => {
  console.log('User logged in:', data.user);
});

Remove Listener

const unsubscribe = EventManager.on('event', handler);
unsubscribe();  // Remove listener

API Reference

EventManager.on(event, handler)

Subscribe to event

Parameter Type Description
event string Event name
handler function Event handler

Returns: Function - Unsubscribe function

const unsubscribe = EventManager.on('data:loaded', (data) => {
  console.log('Data:', data);
});

// Later...
unsubscribe();

EventManager.once(event, handler)

Subscribe once (auto-remove after first call)

EventManager.once('init:complete', () => {
  console.log('Initialized!');
});

EventManager.emit(event, data?)

Emit event

Parameter Type Description
event string Event name
data any Event data
EventManager.emit('cart:update', { items: cart.items });

EventManager.off(event, handler?)

Remove listener(s)

Parameter Type Description
event string Event name
handler function Specific handler (optional)
// Remove specific handler
EventManager.off('event', myHandler);

// Remove all handlers for event
EventManager.off('event');

EventManager.clear()

Remove all listeners

EventManager.clear();

Event Naming Convention

Use namespaced events:

// Format: [component]:[action]
'user:login'
'user:logout'
'cart:add'
'cart:remove'
'modal:open'
'modal:close'
'form:submit'
'form:error'

Real-World Examples

Component Communication

// ComponentA.js - Sender
function addToCart(product) {
  cart.push(product);
  EventManager.emit('cart:add', { product, cart });
}

// ComponentB.js - Receiver
EventManager.on('cart:add', (data) => {
  updateCartBadge(data.cart.length);
});

// ComponentC.js - Receiver
EventManager.on('cart:add', (data) => {
  showNotification(`Added ${data.product.name}`);
});

App State Changes

// Auth events
EventManager.on('auth:login', (data) => {
  showUserMenu(data.user);
  loadUserPreferences();
});

EventManager.on('auth:logout', () => {
  clearUserMenu();
  resetApp();
});

// Route events
EventManager.on('route:changed', (data) => {
  trackPageView(data.path);
  updateActiveNav(data.path);
});
// Open modal and wait for result
function openConfirmModal(message) {
  return new Promise((resolve) => {
    EventManager.once('confirm:result', (result) => {
      resolve(result.confirmed);
    });

    EventManager.emit('modal:open', {
      type: 'confirm',
      message
    });
  });
}

// Usage
const confirmed = await openConfirmModal('Delete this item?');
if (confirmed) {
  deleteItem();
}

Form Validation

// Global validation listener
EventManager.on('form:validate', (data) => {
  console.log('Form validated:', data.valid ? 'PASS' : 'FAIL');
});

// Form emits validation events
function validateForm(form) {
  const valid = checkFields(form);
  EventManager.emit('form:validate', { form: form.id, valid });
  return valid;
}

Clean Up on Unmount

class MyComponent {
  constructor() {
    this.unsubscribers = [];
  }

  mount() {
    // Subscribe and save unsubscribe functions
    this.unsubscribers.push(
      EventManager.on('event1', this.handler1.bind(this)),
      EventManager.on('event2', this.handler2.bind(this))
    );
  }

  unmount() {
    // Clean up all subscriptions
    this.unsubscribers.forEach(unsub => unsub());
    this.unsubscribers = [];
  }
}

Framework Events

Event When Triggered
app:ready App initialized
route:changed Route changed
auth:login User logged in
auth:logout User logged out
state:changed Global state changed
modal:open Modal opened
modal:close Modal closed
notification:show Notification shown

Common Pitfalls

⚠️ 1. Unsubscribe to Prevent Memory Leaks

// ❌ Never unsubscribe
EventManager.on('event', handler);

// ✅ Save and call unsubscribe
const unsub = EventManager.on('event', handler);
// When done...
unsub();

⚠️ 2. Avoid Circular Events

// ❌ Circular - causes infinite loop
EventManager.on('a', () => EventManager.emit('b'));
EventManager.on('b', () => EventManager.emit('a'));

// ✅ Use flags or debounce
let processing = false;
EventManager.on('a', () => {
  if (processing) return;
  processing = true;
  EventManager.emit('b');
  processing = false;
});