Skip to content
Open
81 changes: 81 additions & 0 deletions docs/docs/advanced/event-dispatcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Event Dispatcher System
description: How the webforJ event dispatcher system works and how to use it for event-driven programming.
sidebar_position: 50
---

The webforJ event dispatcher system provides a flexible and type-safe way to handle events in your app. It allows you to register listeners for specific event types and dispatch events to those listeners, enabling event-driven programming across components.


## `EventDispatcher`

[`EventDispatcher`](https://webforj.com/javadoc/com/webforj/dispatcher/EventDispatcher.html) is a minimalistic event manager for dispatching events to listeners. It's not tied to UI components or element events.

### Available APIs

- `addListener(Class<T> eventClass, EventListener<T> listener)`: Registers a listener for a specific event type. Returns a `ListenerRegistration<T>` for later removal.
- `removeListener(Class<T> eventClass, EventListener<T> listener)`: Removes a specific listener for the given event type.
- `removeAllListeners(Class<T> eventClass)`: Removes all listeners for a given event type.
- `removeAllListeners()`: Removes all listeners from the dispatcher.
- `dispatchEvent(T event)`: Notifies all listeners of the given event.

<ComponentDemo
path='/webforj/eventdispatchercustomevent'
javaE='https://raw.githubusercontent.com/webforj/webforj-documentation/refs/heads/main/src/main/java/com/webforj/samples/views/advanced/EventDispatcherCustomEventView.java'
height = '300px'
/>

### Creating and registering listeners

```java
import com.webforj.dispatcher.EventDispatcher;
import com.webforj.dispatcher.EventListener;
import java.util.EventObject;

// Create the dispatcher
EventDispatcher dispatcher = new EventDispatcher();

// Register a listener
ListenerRegistration<EventObject> reg = dispatcher.addListener(EventObject.class, event -> {
// handle event
System.out.println("Event received: " + event);
});

// Remove a listener
reg.remove();
// or
dispatcher.removeListener(EventObject.class, reg.getListener());

// Dispatch an event
dispatcher.dispatchEvent(new EventObject(this));
```

## Advanced registration options

For advanced scenarios, you can register listeners with additional options using `ElementEventOptions`. These options allow you to:
- Add custom data to the event payload
- Debounce or throttle event firing
- Filter events based on conditions
- Execute JavaScript before the event is fired (for UI events)

Example:

```java
ElementEventOptions options = new ElementEventOptions();
options.addData("value", "event.target.value");
options.setDebounce(300); // Debounce by 300ms
options.setFilter("event.target.value.length > 2");

myComponent.addEventListener("input", event -> {
String value = (String) event.getData().get("value");
System.out.println("Input value: " + value);
}, options);
```

## Best practices

- Always remove listeners when they're no longer needed to avoid memory leaks.
- Use the provided event payload methods to access event data efficiently, avoiding unnecessary client-server round-trips.
- Prefer using component APIs for event handling unless you have advanced requirements.
- Use registration options (payload, debounce, filter) to optimize performance and event data handling.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [vale] reported by reviewdog 🐶
[webforJ.BeDirect] Avoid using 'optimize performance and event'. Focus more on explicitly giving details about the feature.


Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.webforj.samples.views.advanced;

import com.webforj.dispatcher.EventDispatcher;
import com.webforj.router.annotation.FrameTitle;
import com.webforj.router.annotation.Route;
import com.webforj.component.button.Button;
import com.webforj.component.Composite;
import com.webforj.component.html.elements.Div;
import java.util.EventObject;

@Route
@FrameTitle("Event Dispatcher")
public class EventDispatcherCustomEventView extends Composite<Div> {
private final EventDispatcher dispatcher = new EventDispatcher();

/**
* A custom event that carries a message string.
*/
public static class CustomMessageEvent extends EventObject {
private final String message;

public CustomMessageEvent(Object source, String message) {
super(source);
this.message = message;
}

public String getMessage() {
return message;
}
}

public EventDispatcherCustomEventView() {
Button button = new Button("Fire Custom Event");

Div statusText = new Div("waiting for custom event");
statusText.setStyle("border", "2px solid #333");
statusText.setStyle("padding", "8px 24px");
statusText.setStyle("margin-top", "24px");
statusText.setStyle("border-radius", "6px");
statusText.setStyle("font-size", "1.1em");
statusText.setStyle("background", "#fafbfc");

// Center the content using flexbox styles on the root Div
Div root = this.getBoundComponent();
root.setStyle("display", "flex");
root.setStyle("flex-direction", "column");
root.setStyle("justify-content", "center");
root.setStyle("align-items", "center");
root.setStyle("height", "100vh");

root.add(button);
root.add(statusText);

// Register a listener for the custom event
dispatcher.addListener(CustomMessageEvent.class, event -> {
statusText.setText("received custom event ");
button.setEnabled(false);
});

// Fire the custom event with a message when the button is clicked
button.onClick(e -> dispatcher.dispatchEvent(new CustomMessageEvent(this, "Hello from custom event!")));
}
}
Loading