52

I was wondering if anyone can help me understand how exactly to create different Custom event listeners.

I don't have a specific case of an event but I want to learn just in general how it is done, so I can apply it where it is needed.

What I was looking to do, just incase some folks might need to know, was:

var position = 0;

for(var i = 0; i < 10; i++)
{
    position++;
    if((position + 1) % 4 == 0)
    {
        // do some functions
    }
}
4
  • See this other question Commented Mar 12, 2012 at 17:40
  • You can use a library such as jQuery to create custom events and listeners. Have a look at fuelyourcoding.com/… and api.jquery.com/trigger Commented Mar 12, 2012 at 17:41
  • 11
    How is the code you posted related to event handling? Do you want to run this code as response to an event? Commented Mar 12, 2012 at 17:42
  • check this link Commented Mar 12, 2012 at 17:51

4 Answers 4

73
var evt = document.createEvent("Event");
evt.initEvent("myEvent",true,true);

// custom param
evt.foo = "bar";

//register
document.addEventListener("myEvent",myEventHandler,false);

//invoke
document.dispatchEvent(evt);

Here is the way to do it more locally, pinpointing listeners and publishers: http://www.kaizou.org/2010/03/generating-custom-javascript-events/

Sign up to request clarification or add additional context in comments.

3 Comments

Note: The createEvent method is deprecated. Use event constructors instead.
Event constructors are not supported in IE.
Try dom4 if you want to use CustomeEvent on IE. This is a cross browser polyfill that provides DOM 4 Level 4 interfaces. With this you can use CustomEvent on IE 8 or above.
46

Implementing custom events is not hard. You can implement it in many ways. Lately I'm doing it like this:

/***************************************************************
*
*   Observable
*
***************************************************************/
var Observable;
(Observable = function() {
}).prototype = {
    listen: function(type, method, scope, context) {
        var listeners, handlers;
        if (!(listeners = this.listeners)) {
            listeners = this.listeners = {};
        }
        if (!(handlers = listeners[type])){
            handlers = listeners[type] = [];
        }
        scope = (scope ? scope : window);
        handlers.push({
            method: method,
            scope: scope,
            context: (context ? context : scope)
        });
    },
    fireEvent: function(type, data, context) {
        var listeners, handlers, i, n, handler, scope;
        if (!(listeners = this.listeners)) {
            return;
        }
        if (!(handlers = listeners[type])){
            return;
        }
        for (i = 0, n = handlers.length; i < n; i++){
            handler = handlers[i];
            if (typeof(context)!=="undefined" && context !== handler.context) continue;
            if (handler.method.call(
                handler.scope, this, type, data
            )===false) {
                return false;
            }
        }
        return true;
    }
};

The Observable object can be reused and applied by whatever constructor needs it simply by mixng the prototype of Observable with the protoype of that constructor.

To start listening, you have to register yourself to the observable object, like so:

var obs = new Observable();
obs.listen("myEvent", function(observable, eventType, data){
    //handle myEvent
});

Or if your listener is a method of an object, like so:

obs.listen("myEvent", listener.handler, listener);

Where listener is an instance of an object, which implements the method "handler".

The Observable object can now call its fireEvent method whenever something happens that it wants to communicate to its listeners:

this.fireEvent("myEvent", data);

Where data is some data that the listeners my find interesting. Whatever you put in there is up to you - you know best what your custom event is made up of.

The fireEvent method simply goes through all the listeners that were registered for "myEvent", and calls the registered function. If the function returns false, then that is taken to mean that the event is canceled, and the observable will not call the other listeners. As a result the entire fireEvent method will return fasle too so the observable knows that whatever action it was notifying its listeners of should now be rolled back.

Perhaps this solution doesn't suit everybody, but I;ve had much benefit from this relatively simple piece of code.

4 Comments

Where do you call this.fireEvent("myEvent", data) from? I'm confused about the "this"scope.
I wrote: "The Observable object can now call its fireEvent method". So, this refers to the instance of the observable object (or an object that mixes in its methods)
Is there any significant difference in behaviour/performance between a solution like the one above and one that creates, adds and despatches custom events on the document DOM object?
@Pappa I don't know. I started doing this to have something that works everywhere. createEvent and CustomEvent constructor aren't supported everywhere.
14

From here:

https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events

// create the event
const event = new Event('build');

// elem is any element
elem.dispatchEvent(event);


// later on.. binding to that event
// we'll bind to the document for the event delegation style. 
document.addEventListener('build', function(e){
   // e.target matches the elem from above
}, false);

1 Comment

On the same page developer.mozilla.org/en-US/docs/Web/Guide/Events/… it mentions that this is not supported in IE.
9

Here is a really simple (TypeScript/Babelish) implementation:

const simpleEvent = <T extends Function>(context = null) => {
    let cbs: T[] = [];
    return {
        addListener: (cb: T) => { cbs.push(cb); },
        removeListener: (cb: T) => { let i = cbs.indexOf(cb); cbs.splice(i, Math.max(i, 0)); },
        trigger: (<T> (((...args) => cbs.forEach(cb => cb.apply(context, args))) as any))
    };
};

You use it like this:

let onMyEvent = simpleEvent();
let listener = (test) => { console.log("triggered", test); };
onMyEvent.addListener(listener);
onMyEvent.trigger("hello");
onMyEvent.removeListener(listener);

Or in classes like this

class Example {
    public onMyEvent = simpleEvent(this);
}

If you want plain JavaScript you can transpile it using TypeScript playground.

1 Comment

This is pretty damm elegant.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.