• Stars
    star
    461
  • Rank 95,051 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 13 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An implementation of the mediator pattern for asynchronous events in Javascript

Mediator.js

Build Status

Version 0.11.0

A light utility class to help implement the Mediator pattern for easy eventing

Mediator is a simple class that allows you to register, unregister, and call subscriber methods to help event-based, asyncronous programming. Its purpose is to make the usage of WebSockets, Ajax calls, DOM events, or any other asynchronous operations easy to maintain and test.

Mediator has no dependencies on any other libraries.

1.12kb, minifed and gzipped

Why?

My specific use case: bind elements easily for WebSocket callbacks. But, you may find usage in it for all kinds of things: as an event management system, to decouple calls between javascript functions, Ajax request callbacks, and more. There's an excellent online book that talks about Mediators more in detail by Addy Osmani.

Usage

Using in Node

The package is in NPM as mediator-js. Include it in your project like so:

var Mediator = require("mediator-js").Mediator,
    mediator = new Mediator();

mediator.subscribe("wat", function(){ console.log(arguments); });
mediator.publish("wat", 7, "hi", { one: 1 });

Using in the Browser

Mediator.js is compatible with browser module-loading solutions, including but not limited to Browserify, Almond.js, Require.js, and others.

Note: if using AMD / Almond module loading, use the NPM package name: require("mediator-js").Mediator

<script src="/js/Mediator.min.js"></script>

<script>
  var Mediator = require("mediator-js").Mediator,
      mediator = new Mediator();

  mediator.subscribe("wat", function(){ console.log(arguments); });
  mediator.publish("wat", 7, "hi", { one: 1 });
</script>

API

You can register events with the mediator two ways using channels. You can add a predicate to perform more complex matching. Instantiate a new mediator, and then you can being subscribing, removing, and publishing.

To use it in the browser, include mediator.min.js from the root here, or the unminified version at lib/mediator.js.

Subscription signature: var mediator = new Mediator();

mediator.subscribe(channel, callback, <options>, <context>);
mediator.publish(channel, <data, data, ... >)
mediator.remove(channel, <identifier>)

Additionally,

  • subscribe: is alias for on and bind
  • publish: is alias for trigger and emit
  • off: is an alias for remove
  • once: can be used to subscribe to an event that should only be fired once.

Subscriber signature:

function(<data, data ...>, channel);

The channel is always returned as the last argument to subscriber functions.

Mediator.subscribe options (all are optional; default is empty):

{
  predicate: function(*args){ ... }
  priority: 0|1|... 
  calls: 1|2|...
}

Predicates return a boolean and are run using whatever args are passed in by the publishing class. If the boolean is true, the subscriber is run.

Priority marks the order in which a subscriber is called.

calls allows you to specify how many times the subscriber is called before it is automatically removed. This is decremented each time it is called until it reaches 0 and is removed. If it has a predicate and the predicate does not match, calls is not decremented.

A Subscriber object is returned when calling Mediator.subscribe. It allows you to update options on a given subscriber, or to reference it by an id for easy removal later.

{
  id, // guid
  fn, // function
  options, // options
  context, // context for fn to be called within
  channel, // provides a pointer back to its channel
  update(options){ ...} // update the subscriber ({ fn, options, context })
}

Examples:

var mediator = new Mediator();

// Alert data when the "message" channel is published to
// Subscribe returns a "Subscriber" object
mediator.subscribe("message", function(data){ alert(data); });
mediator.publish("message", "Hello, world");

// Alert the "message" property of the object called when the predicate function returns true (The "From" property is equal to "Jack")
var predicate = function(data){ return data.From === "Jack" };
mediator.subscribe("channel", function(data){ alert(data.Message); }, { predicate: predicate });
mediator.publish("channel", { Message: "Hey!", From: "Jack" }); //alerts
mediator.publish("channel", { Message: "Hey!", From: "Audrey" }); //doesn't alert

You can remove events by passing in a channel, or a channel and the function to remove or subscriber id. If you only pass in a channel, all subscribers are removed.

// removes all methods bound directly to a channel, but not subchannels
mediator.remove("channel");

// unregisters *only* MethodFN, a named function, from "channel"
mediator.remove("channel", MethodFN);

You can call the registered functions with the Publish method, which accepts an args array:

mediator.publish("channel", "argument", "another one", { etc: true });

You can namespace your subscribing / removing / publishing as such:

mediator.subscribe("application:chat:receiveMessage", function(data){ ... });

// will call parents of the application:chat:receiveMessage namespace
// (that is, next it will call all subscribers of application:chat, and then
// application). It will not recursively call subchannels - only direct subscribers.
mediator.publish("application:chat:receiveMessage", "Jack Lawson", "Hey");

You can update Subscriber priority:

var sub = mediator.subscribe("application:chat", function(data){ ... });
var sub2 = mediator.subscribe("application:chat", function(data){ ... });

// have sub2 executed first
mediator.getChannel("application:chat").setPriority(sub2.id, 0);

You can update Subscriber callback, context, and/or options:

sub.update({ fn: ..., context: { }, options: { ... });

You can stop the chain of execution by calling channel.stopPropagation():

// for example, let's not post the message if the from and to are the same
mediator.subscribe("application:chat", function(data, channel){
  alert("Don't send messages to yourself!");
  channel.stopPropagation();
}, options: {
  predicate: function(data){ return data.From == data.To },
  priority: 0
});

Changelog

Version 0.11.0

Version 0.10.1

  • Accepted a PR that fixed some AMD require issues, and allowed upwards- recursing events to fire on events even where the most-specific event is not fired (a listener on "application:chat:message" will fire on an event like "application:chat:message:jack", even if there's no matching listenener on "jack".) #45

Version 0.9.8

  • Accepted a ton of PRs from tbusser that fixed some issues and improved performance.

Version 0.9.7

  • Fixed bug where subscribers that failed predicates were decrementing calls.

Version 0.9.6

  • Fixed AMD-style export; export constructor, not instance

Version 0.9.5

  • Fixed issue with requring from node

Version 0.9.4

  • Fixed issue with auto-removing subscribers after a maximum amount of calls

Version 0.9.3

  • Make AMD name match npm package name mediator-js. (Previously used Mediator.js.)

Version 0.9.1

  • Fixed AMD / define syntax
  • Exposed Mediator.version

Version 0.9.0

  • Reversed order of recursion: now calls parents instead of children channels
  • Lowercase methods
  • Aliases: on and bind are aliased to subscribe, and trigger and emit are bound to publish. off is an alias for remove.
  • Moved tests to mocha from jasmine
  • Supports AMD, requirejs, and browser loading
  • Lots of cleanup around extra variables, and jslinted
  • Published to NPM under "mediator-js"
  • Added travis-ci build

Version 0.6.1

  • Cleaned up some typos
  • Save pointer to channel within subscription
  • Save namespace in channel
  • Fixed bugs in SetPriority

Version 0.6.0

  • Added ability to stop the chain of calls using c.stopPropagation()

Version 0.5.0

  • Added ability to access and update subscribing objects
    • Subscribers now have a unique ID and can be queried by id or by function
    • Subscriber class can have its function, context, or options updated
    • Subscriber priority can be updated post-addition
    • Channels made public by Mediator.GetChannel
    • Added a little performance test

Version 0.4.2

  • Added Priority to calls, allowing you to set callback index

Version 0.4.1

  • Minor internal updates

Version 0.4.0

  • Predicate no longer acts as a channel and is moved to an options object at the end of the subcription call.
  • Signatures changed; context moved to the end of subscriptions
  • Namespacing for subscription binding

License

This class and its accompanying README and are MIT licensed.

In Closing

Have fun, and please submit suggestions and improvements! You can leave any issues here, or contact me at (@ajacksified).

More Repositories

1

song-of-github

Let me play you the song of my contributions.
JavaScript
455
star
2

hubot-plusplus

Welcome to Hubot, where the points don't matter
CoffeeScript
59
star
3

Clark

It's like Spark, but in Coffeescript.
CSS
8
star
4

Craftyjs-Presentation

Lightning talk for a Craftyjs presentation for SF GamesJS
JavaScript
4
star
5

Mustache-RSS-Templates

Simple Atom and RSS 2.0 Templates, in Mustache
4
star
6

performance-tooling

Performance tooling presentation
JavaScript
4
star
7

coffee-protocol

Classes for implementation of RFC 2325
CoffeeScript
3
star
8

openresty-benchmark

Benchmark testing frameworks against OpenResty
Ruby
2
star
9

Ergojack

Ergodox Infinity Layout
2
star
10

chariot

🐴
JavaScript
2
star
11

react-plugin-system

plugin system for reacts
JavaScript
2
star
12

connect4

Seemed like a good idea at the time
CoffeeScript
1
star
13

express-router

the router from express.js as a package
JavaScript
1
star
14

csswords

What words can you spell using css?
JavaScript
1
star
15

the-dark-side-of-the-performance-moon

JavaScript
1
star
16

ajacksified.github.com

A Better Way
ApacheConf
1
star
17

dotfiles

config
Vim Script
1
star
18

bard

Node bootstrap. Server + Client rendering. Mustache and Backbone. Sockets and REST.
JavaScript
1
star
19

how-to-mocha

Simple Mocha / Chai examples.
JavaScript
1
star
20

react-mutator

Query and mutate react elements at render time
JavaScript
1
star
21

chariot-example

an example for chariot
JavaScript
1
star
22

wowsuch

wow such code many commit
JavaScript
1
star
23

how-to-hubot

A presentation on how to do a Hubot
JavaScript
1
star
24

Jasmine-Backbone-SASS-HTML5-Boilerplate

A project boilerplate for SCSS, Jasmine, Coffeescript, and html 5
JavaScript
1
star
25

websockets-workshop

WebSockets Workshop: Slides & Demo
CSS
1
star
26

watwatwat

watwatwat
HTML
1
star
27

quorra

tetrahedral and hexagonal isometric grid placement engine
JavaScript
1
star
28

the-storms-gaze

JavaScript
1
star