Github Issue we will ‘hack':

“I was curious if there was a better way to bind on multiple events at once…”

Wouldn’t it be nice to bind multiple events to the same expression in our Angular2 Templates? It would probably look like this if we did so:

<div (click,submit,mouseenter)=’foo($event)’></div>

EventManager

In my last post, I described how to create custom events by extending EventManagerPlugin. The EventManagerPlugin is an extendable class which allows you to specify behavior for event strings.

In fact, it is extended in multiple places in the Angular2 source to implement the normal event bindings you are already using.

EventManagerPlugins (AKA the EVENT_MANAGER_PLUGINS provider/OpaqueToken) lives as a private member of EventManager.

How it works

When you add an event to an angular template, while the DOM tree is being parsed, the DomRenderer’s instance calls listen().

The listen and listenGlobal functions which call their instance of EventManager

As you can see, listen() this then calls the EventManager’s instance function addEventListener(). EventManager then searches through its list of registered EventManagerPlugins calling their supports() function and passing the eventName.

_findPluginFor(eventName: string) passes the event in question, and then iterates though its plugins looking for a plugin that “supports()” the event name.

This function returns either true or false telling the EventManager whether or not this plugin can/is supposed to handle this custom event. When a valid plugin is found, the manager calls that plugin’s version of addEventListener() performing the custom action.

Step 1: Creating a new plugin

Now that we have an idea how this all works, lets implement a new plugin.

Like I mentioned above, we want to have multiple events on our Angular2 templates tie to the same expression like this:

<div (click,submit,mouseenter)=’foo($event)’></div>

If thats the case the rules for our supports() function should be pretty clear. We need a string which has (1 or more) commas in it, that separate event names. We should also handle when people put something stupid in like “(,click)”. So I wrote my supports() function as follows:

Also includes a method I can use to get an array of events.

This will allows EventManager to delegate event strings like “click,submit,mousedown” to this plugin.

Step 2: implementing the eventListeners

Now that we have implemented supports(), EventManager will now call plugin.addEventListener() so the plugin can define its custom behavior.

Our custom behavior is simple: “add event listeners for all the events in the eventArray that we parsed”.

Fail Number 1

This worked, however custom events wouldn’t trigger for their respective plugins.

My first attempt as you can see has me using DOM.onAndCancel(element, singleEventName, outsideHandler); This is the equivalent of conveniently performing the native addEventListener() and removeEventListener().

This however came with some issues. For example when I used “(clickOutside,click,submit)” which includes a custom event (created from another plugin), it did not fire because it was executed in the current plugin’s context.

Success!!!

Wait, but we do have the EventManager instance available, instead of attaching the events in this plugin, why don’t we pass EventManager the events, and let it do its job and figure out which plugins should use them.

So I refactored the code to look like this:

Using this.manager.addEventListener() to send events back to be called by the appropriate plugin.

Step 3: add it to EVENT_MANAGER_PLUGINS

This worked like a charm!!!!! All that was left to do was to implement the plugin and bootstrap it.