Events

Think of event functions as state changers. Their only job is to react to triggers (such as user interactions and program events) and make modifications to the component's state.

Events structure

When adding events to a component, organize them within objects grouped by selectors (use CSS style selectors):

FamousFramework.component('example', {
    events: {
        'selector1': {
            'event-name1': function() {
                // do something
            },
            'event-name2': function(){
                // do something else
            }
        },
        'selector2': {
            'event-name1': function(){
                // do something else here
            }   
        }
    }
});

The event object selectors specify which event functions will be attached to the corresponding elements in the tree. Event listeners can either be traditional DOM events ('click', 'mousedown', etc) or custom programmatic events.

Modifying the state

Events, and only events, can modify a module's state values. Via dependency injection, event functions can read and write to these values through the $state object.

FamousFramework.component('example', {
    events: {
        '.nav-button': {
            'click': function($state, $payload) {
                 // get the 'clickCount' value (zero)
                 var oldValue = $state.get('clickCount');
                 // increment the counter by 5 
                 $state.set('clickCount', oldValue + 5);
            }
        }    
    },
    states: {
        clickCount: 0 // will increment by 5 on a click
    }
});

Here, we use $state.get() to grab the state value for clickCount and the .set() method to replace it with a new incremented value. This event function will run every time a '.nav-button' element is clicked.

It's common to dependency-inject a $state instance along with a complementary $payload object, which is the message accompanying the source event. In the example above, the $payload would be a MouseEvent object.

For more on the $state object's API visit the states section.

$lifecycle events

The $lifecycle event group allows you to listen for special events throughout the life of a component. To access these events, provide '$lifecycle' as a selector to the events object instead of a selector.

Here, we set the state's positionX value to 250 over a 1000ms period immediately after the component loads.

FamousFramework.component('example', {
    events: {
        '$lifecycle': {
            'post-load': function($state) {
                $state.set('positionX', 250, { duration:1000 });
            }
        }
    }
});

$lifecycle events include:

Custom events

To broadcast a custom event message, you'll need to dependency-inject a $dispatcher instance into your event function:

FamousFramework.component('parent', {
    events: {
        '$lifecycle': {
            'post-load': function($dispatcher) {
                $dispatcher.broadcast('parent-loaded', {loaded: true});
            }
        }
    }
});

Components can listen to messages emitted by any component declared in their tree.

FamousFramework.component('child', {
    events: {
        '#foo': {
            'parent-loaded': function($payload) {
                // Do business logic here
            }
        }
    },
    tree: `<node id="foo"></node>`
});

Private vs. public events

Events within the $private group will only be triggered by a scene's own $self behaviors.

FamousFramework.component('example', {
    behaviors: {
        '$self': {
            'foo': function(...){...}
        }
    },
    events: {
        '$private': {
            'foo': function(...){...}
        }
    }
});

By contrast, '$public' is a special event group name that exposes event functions to other components. All core Framework components use $public functions to expose an interface into their rendering logic.

How behaviors are applied

When you apply a behavior to some node in your scene's tree, you're really just sending a message to that descendant. The message will be received if the target component exposes an equivalently named event.

Take this example of a scene that is applying a 'size' behavior to a ui-element component:

FamousFramework.component('example', {
    behaviors: {
        '#el': {
            'size': function(){ return [200, 200]; }
        }
    },
    tree: `<node id="el"></node>`
});

As it turns out, the node base component defines a event called 'size' that it makes accessible to parent components. Its implementation looks (roughly) like this:

FamousFramework.component('famous:core:node', {
    events: {
        // '$public' is a special event group name that says
        // "I am exposing these functions to other components"
        '$public': {
            'size': function($state, $payload) {
                // $state is this scene's own state-manager
                // $payload is the message that was sent, e.g. [200, 200]
                // This component now has to decide how to change
                // its internals in response to the message
            }
        }
    }
});

Whenever example's behavior 'size' is fired, the framework instantiates a new message with the behavior's return value as the message's contents. It then routes the message to all nodes in the tree that match the '#el' selector.

If any of those matching target nodes expose a "public" event that matches the message's name ('size'), then that event will be fired, with the injected $payload argument given to represent the value of the message's contents.