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
thiscontext in a magical and non-intuitive way - it listens for the
clickevent 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
actionhelper, which has completely different functionality from theactionmodifier
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 theonclickattribute, which is then reflected to the actual DOM node'sonclickproperty. 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: