Home

Events

Events are one of the most powerful features of JavaScript. In the user input section, we explored how to use them to capture user actions. But our application can also use event internally to create other logic. We call this type of usage program events.

Emitting and listening to events is a great way to achieve this-action-follows-that-style interactivity without the downsides you might encounter when creating UI logic with, say, functions.

Emit and listen with EventHandler

Events are a way of moving information between program modules. In Famo.us, we can emit and listen to program events using a class called EventHandler. In this example, we have a simple emit-and-listen pattern using one event handler. Clicking the surface will emit a 'hello' event, which a handler will listen to downstream.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var StateModifier = famous.modifiers.StateModifier;
var EventHandler = famous.core.EventHandler;

var mainContext = Engine.createContext();
var surface;
createSurface();
var eventHandler = new EventHandler();

surface.on('click', function() {
  eventHandler.emit('hello');
});

eventHandler.on('hello', function() {
  surface.setContent('heard hello');
});

function createSurface() {
  surface = new Surface({
    size: [100, 100],
    content: 'click me to emit "hello"',
    properties: {
      color: 'white',
      textAlign: 'center',
      backgroundColor: '#fa5c4f'
    }
  });

  mainContext.add(surface);
}

As you can see, we use the EventHandler instance’s .on() method to listen to specific events. We use its .emit() method to emit a named event.

Listening to many events with .subscribe()

More commonly, you’ll use multiple event handlers to communicate between different application modules. In this example, we have two event handlers, A and B. Event handler A emits 'hello' when surface A is clicked. Event handler B listens for the 'hello' event and calls surface B to set its content when the event is triggered.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var StateModifier = famous.modifiers.StateModifier;
var EventHandler = famous.core.EventHandler;

var mainContext = Engine.createContext();

var surfaceA, surfaceB;
createSurfaces();

var eventHandlerA = new EventHandler();
var eventHandlerB = new EventHandler();

surfaceA.on('click', function() {
  eventHandlerA.emit('hello');
  surfaceA.setContent('said hello');
});

eventHandlerB.subscribe(eventHandlerA);

eventHandlerB.on('hello', function() {
  surfaceB.setContent('heard hello');
});

function createSurfaces() {
  surfaceA = new Surface({
    size: [100, 100],
    content: 'A<br>click me to say hello',
    properties: {
      color: 'white',
      textAlign: 'center',
      backgroundColor: '#fa5c4f'
    }
  });

  surfaceB = new Surface({
    size: [100, 100],
    content: 'B',
    properties: {
      color: 'white',
      textAlign: 'center',
      backgroundColor: '#fa5c4f'
    }
  });

  var modifierB = new StateModifier({
    origin: [1, 1],
    align: [1, 1]
  });

  mainContext.add(surfaceA);
  mainContext.add(modifierB).add(surfaceB);
}

By using the EventHandler instance’s .subscribe() method, we can tell one event handler to listen to all events emitted by the other one.

Going the other direction with .pipe()

The EventHandler instance’s .pipe() method is the inverse of .subscribe(). With .pipe(), we transmit all events to another object. The end result is the same, but the implementation is slightly different. It’s up to you to decide when to use .pipe() and when to use .subscribe().

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var StateModifier = famous.modifiers.StateModifier;
var EventHandler = famous.core.EventHandler;

var mainContext = Engine.createContext();

var surfaceA, surfaceB;
createSurfaces();

var eventHandlerA = new EventHandler();
var eventHandlerB = new EventHandler();

surfaceA.on('click', function() {
  eventHandlerA.emit('hello');
  surfaceA.setContent('said hello');
});

eventHandlerA.pipe(eventHandlerB);

eventHandlerB.on('hello', function() {
  surfaceB.setContent('heard hello');
});

function createSurfaces() {
  surfaceA = new Surface({
    size: [100, 100],
    content: 'A<br>click me to say hello',
    properties: {
      color: 'white',
      textAlign: 'center',
      backgroundColor: '#fa5c4f'
    }
  });

  surfaceB = new Surface({
    size: [100, 100],
    content: 'B',
    properties: {
      color: 'white',
      textAlign: 'center',
      backgroundColor: '#fa5c4f'
    }
  });

  var modifierB = new StateModifier({
    origin: [1, 1],
    align: [1, 1]
  });

  mainContext.add(surfaceA);
  mainContext.add(modifierB).add(surfaceB);
}

Program events and views

Views are important tools in Famo.us to help keep our code organized and modularized. One way views help us do this is by providing two (internally created) event handlers: an input handler and an output handler. These are ready to use with any object that inherits from the View prototype.

When you pipe into a view or subscribe from a view, you’re actually piping into or subscribing from the input event handler of a view, called view._eventInput. Conceptually, a view’s input handler is the aggregation point of all the events coming into that view. The view can then decide what to do with those events by listening on its _eventInput.

// @famous-block
// @famous-block-option preset famous-0.3.0-globals
var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var View = famous.core.View;

var mainContext = Engine.createContext();

var myView = new View();
mainContext.add(myView);

var surface = new Surface({
  size: [100, 100],
  content: 'click me',
  properties: {
    color: 'white',
    textAlign: 'center',
    backgroundColor: '#fa5c4f'
  }
});

myView.add(surface);

surface.pipe(myView);
// alternatively, myView.subscribe(surface);

// normally inside view module's code
myView._eventInput.on('click', function() {
  surface.setContent('hello');
});

Next: Using HTML and CSS with Famo.us »