There are two kinds of {{action}} in Ember Classic: the modifier, and the helper—and both of them had their own special sauce. Octane simplifies this by providing the {{on}} modifier and the {{fn}} helper, each of which does just one thing.

{{on}}

In Ember Classic, the {{action}} modifier can be applied to a component to bind its event handling, handling click events by default, and it looks up methods in the actions object on a backing class by string name:

<button type="button" {{action "doIt" on="doubleClick"}}>Click me twice!</button>

There are three changes for using {{on}} instead:

  1. It requires the name of an event for its first argument, so the implicit behavior is removed. This makes it clearer what it will do, and also makes it easier to spot accessibility issues (like putting click events on a <div>—don't do that!).
  2. The actions object is no longer used; instead, any method on the backing class may be used—so simply doing this.doIt is appropriate.
  3. The names of the events are not the names of the Ember Classic event names, but the native event names. Here, for example, dblclick instead of doubleClick.

Putting them all together, and we would rewrite the example above like this:

<button type="button" {{on "dblclick" this.doIt}}>Click me twice!</button>

<aside> 💡 Note: the action on the backing class should always be decorated with @action to make sure it's safe to call and pass around! The details: @action binds the context of the method: it keeps the this the same no matter what—like using the bind method.

</aside>

{{fn}}

In Ember Classic, the {{action}} helper does two things: partial application of arguments, and looking up methods in the actions object on a backing class. So for example, when passing an action to a component:

<FancyButton @onClick={{action "doIt" 1}} />

Then in the body of FancyButton, we might have something like this:

<button type="button" {{on "click" (action @onClick "two")}}>click!</button>

Here, the doIt method on the backing class would receive both 1 and "two" as arguments.

This ability to partially apply arguments is very useful, so we now do that with {{fn}}. As noted above in the discussion of {{on}}, we no longer need the ability to look up values in the actions object!

We would rewrite the above example like this:

<FancyButton @onClick={{fn this.doIt 1}} />