Pub.dev package GitHub repository

Event Emitter

An Event-based system, highly inspired by NodeJS's Event Emitter. This implementation uses generic types to allow for multiple data types while being very intuitive.

Based on JavaScript and suitable for Dart and Flutter with type safety.

Features

  • Attach multiple listeners to an event emitter.
  • Listen to events with a specific event type and data type.
  • Emit an event of a specific type to be broadcasted to all listeners.
  • Type safety, only the right type will be passed in.
  • Use callbacks with EventEmitter.
  • Use streams with StreamEventEmitter.
  • Can be extended to create custom event emitters and events.
  • Custom events can hold custom data to be used in the listeners.

Getting started

Install it using pub:

dart pub add events_emitter

And import the package:

import 'package:events_emitter/events_emitter.dart';

Usage

final events = EventEmitter();

events.on('message', (String data) => print('String: $data'));
events.on('message', (int data) => print('Integer: $data'));

events.emit('message', 'Hello World');
events.emit('message', 42);

// [Output]
// String: Hello World
// Integer: 42

To remove a specific listener, you can use the subscription to stop it.

final listener = events.on('message', ... ));
listener.cancel();

Remove listeners, by targeting an event type, data type and callback.

// Remove all listeners
events.off();

// Remove listeners of data type `String`
events.off<String>();

// Remove listeners on event type `message`
events.off(type: 'message');

// Remove listeners of data type `String` on event type `message`
events.off<String>(type: 'message');

Listeners

Listeners are attached to an event emitter and are called when an event matches its signature, they can be added manually for flexibility.

final events = EventEmitter();
  ...
final listener = EventListener('message', (String data) => print('String: $data'));
events.addEventListener(listener);
  ...
listener.cancel();

Properties can be set on the listener to change its behavior:

  • once: If set to true, the listener will be removed after the first call.
  • protected: If set to true, the listener will be immune to events.off().

Add callbacks to the listener:

  • onAdd: Called when the listener is added to the event emitter.
  • onRemove: Called when the listener is removed from the event emitter.
  • onCall: Called when the listener is called.
  • onCancel: Called when the listener is canceled.
final events = EventEmitter();
  ...
final listener = EventListener(
  'message',
  (String data) => print(data),
  
  once: false,
  protected: false,

  onAdd: (emitter) => print('Added to emitter'),
  onRemove: (emitter) => print('Removed from emitter'),
  onCall: (data) => print('Called with data: $data'),
  onCancel: () => print('Listener canceled'),
);

Why is this package different?

events_emitter implements the Event-based system using callbacks and streams, making it very easy to use and very flexible, allowing you to choose the best way to use it. If you need to fit your needs, you can extend the EventEmitter and Event classes to create your own custom interface.

And something very important, events_emitter allows you to use type-safe events, so you can use the same event type for different data types. Not having to worry about the wrong type being passed in.

Example

The EventEmitter class can be used by itself or can be extended to create a custom event emitter.

import 'package:events_emitter/events_emitter.dart';

class Person extends EventEmitter {
    String name;

    Person(this.name);

    void say(String message) => emit('say', message);
    void eat(String food) => emit('eat', food);
    void jump(double height) => emit('jump', height);
}

void main() {
  final person = Person('John');

  person.on('say', (String message) => print('${person.name} said: $message'));
  person.on('eat', (String food) => print('${person.name} ate $food'));
  person.on('jump', (double height) => print('${person.name} jumped $height meters'));

  person.say('I\'m a human!');
  person.eat('apple');
  person.jump(0.5);

  // [Output]
  // John said: I'm a human!
  // John ate apple
  // John jumped 0.5 meters
}

More examples: