On Modifier: A first look
Learn about the newest – and hopefully last! – way to handle events in Ember. Octane approved.
Summary
Let's experiment with the new {{on}}
modifier that shipped with Ember 3.11, and is the new recommended way to handle events in Ember.
We'll take a look at an existing template in EmberMap's code base:
<button onclick={{action 'increasePlaybackRate'}}>
{{fa-icon 'plus'}}
</button>
Currently, we're using closure actions to wire up this click event.
Closure actions are one of two existing ways to wire up actions in Ember. The other way is using the action
modifier:
<button {{action 'increasePlaybackRate'}}>
{{fa-icon 'plus'}}
</button>
The action modifier is the original way events were handled in Ember, and it has some drawbacks:
- it binds the correct
this
context in a magical and non-intuitive way - it listens for the
click
event by default, and uses a strangeon="mouseenter"
option to allow users to change the event - it's become more confusing with the addition of the
action
helper, which has completely different functionality from theaction
modifier
When closure actions were introduced, they improved on the action modifier in many ways. But they too have some drawbacks:
- the
<div onclick={{action 'handleClick'}}>
syntax works because of an inconsistent DOM API, reflection. The template is setting theonclick
attribute, which is then reflected to the actual DOM node'sonclick
property. This ambiguity causes a few problems: it doesn't work the same for all events, and it's not robust to server-side rendering.
The {{on}}
modifier was introduced to address these shortcomings. It looks like this:
<button {{on 'click' (action 'increasePlaybackRate')}}>
{{fa-icon 'plus'}}
</button>
and it's effectively sugar for the addEventListener
API:
buttonEl.addEventListener('click', this.increasePlaybackRate);
There are several benefits to {{on}}
:
- it's explicit
- it works consistently for all events
- it works with web components
- it is robust to SSR, because all modifiers are stripped out and ignored in a server-side environment
- it can be used multiple times
The biggest thing to note is that on
does not bind this
context. It's important to understand this, and the role it will play along with the other new primitives coming to Octane, notably the action
decorator and the fn
modifier. Those will be addressed in a future video.
on
is solely about setting up (and tearing down) event listeners via the addEventListener
API, all from templates. action
can still be used to bind the correct context.
<button {{on 'click' (action 'increasePlaybackRate')}}>
{{fa-icon 'plus'}}
</button>
So give the new on
modifier a shot in your own apps! I think you'll appreciate the clarity and explicitness of this new modifier.
Here's some links for reference: