Skip to content
Implements the `{{on eventName this.someAction}}` element modifier from https://github.com/emberjs/rfcs/pull/353
Branch: master
Clone or download
Latest commit 700ce6d Mar 15, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.dependabot
addon feat: pass through additional parameters Mar 15, 2019
app
config
tests test: fix auto-run assertion for Ember 2.13 Mar 15, 2019
vendor
.editorconfig Initial Commit from Ember CLI v3.7.1 Jan 29, 2019
.ember-cli Initial Commit from Ember CLI v3.7.1 Jan 29, 2019
.eslintignore
.eslintrc.js
.gitignore
.npmignore
.prettierrc style(README): double quotes for hbs Jan 30, 2019
.template-lintrc.js Initial Commit from Ember CLI v3.7.1 Jan 29, 2019
.travis.yml chore(deps): run ember-cli-update Mar 5, 2019
.watchmanconfig Initial Commit from Ember CLI v3.7.1 Jan 29, 2019
CONTRIBUTING.md Initial Commit from Ember CLI v3.7.1 Jan 29, 2019
LICENSE.md
README.md docs(README): explain event options ponyfill Mar 6, 2019
appveyor.yml chore(ci/appveyor): setup AppVeyor with IE11 (#13) Mar 6, 2019
ember-cli-build.js
index.js
package.json 0.8.0 Mar 15, 2019
testem.js
yarn.lock

README.md

ember-on-modifier

Build Status npm version Download Total Ember Observer Score Ember Versions ember-cli Versions code style: prettier dependencies devDependencies

An implementation of the {{on}} element modifier shown in the Modifiers RFC #353. Heavily inspired by @ember/render-modifiers.

Installation

ember install ember-on-modifier

Compatibility

  • Ember.js v2.18 or above
  • ember-cli v2.13 or above

Usage

<button {{on "click" this.onClick}}>
  Click me baby, one more time!
</button>
import Component from '@ember/component';
import { action } from '@ember-decorators/object';

export default class BritneySpearsComponent extends Component {
  @action
  onClick(event: MouseEvent) {
    console.log('I must confess, I still believe.');
  }
}

The @action decorator is used to bind the onClick method to the component instance. Alternatively, you can use the {{action}} or {{bind}} helper in the template.

This is essentially equivalent to:

didInsertElement() {
  super.didInsertElement();

  const button = this.element.querySelector('button');
  button.addEventListener('click', this.onClick);
}

In addition to the above {{on}} will properly tear down the event listener, when the element is removed from the DOM. It will also re-register the event listener, if any of the passed parameters change.

Listening to Multiple Events

You can use the {{on}} modifier multiple times on the same element, even for the same event.

<button
  {{on "click" this.onClick}}
  {{on "click" this.anotherOnClick}}
  {{on "mouseover" this.onMouseEnter}}
>
  Click me baby, one more time!
</button>

Event Options

All named parameters will be passed through to addEventListener as the third parameter, the options hash.

<div {{on "scroll" this.onScroll passive=true}}>
  Lorem Ipsum ...
</div>

This is essentially equivalent to:

didInsertElement() {
  super.didInsertElement();

  const div = this.element.querySelector('div');
  div.addEventListener('scroll', this.onScroll, { passive: true });
}

once

To fire an event listener only once, you can pass the once option:

<button
  {{on "click" this.clickOnlyTheFirstTime once=true}}
  {{on "click" this.clickEveryTime}}
>
  Click me baby, one more time!
</button>

clickOnlyTheFirstTime will only be fired the first time the button is clicked. clickEveryTime is fired every time the button is clicked, including the first time.

Internet Explorer 11 Support

Internet Explorer 11 has a buggy and incomplete implementation of addEventListener: It does not accept an options parameter and sometimes even throws a cryptic error when passing options.

This is why this addon ships a tiny ponyfill for addEventLisener that is used internally to emualte the once option and discard any other options. This means that any options other than once will have no effect in IE11, so do not rely on them in your logic, if you need to support IE11.

Currying / Partial Application

If you want to curry the function call / partially apply arguments, you can do so using the {{action}} or {{bind}} helper:

{{#each this.users as |user|}}
  <button {{on "click" (action this.deleteUser user)}}>
    Delete {{user.name}}
  </button>
{{/each}}
import Component from '@ember/component';
import { action } from '@ember-decorators/object';

interface User {
  name: string;
}

export default class UserListComponent extends Component {
  users: User[] = [{ name: 'Tom Dale' }, { name: 'Yehuda Katz' }];

  @action
  deleteUser(user: User, event: MouseEvent) {
    event.preventDefault();
    this.users.removeObject(user);
  }
}

preventDefault

This addon ships a prevent-default template helper, that you can use like this:

<a href="/" {{on "click" (prevent-default this.someAction)}}>Click me</a>
<a href="/" {{on "click" this.someAction}} {{on "click" (prevent-default)}}>Click me</a>

This is effectively the same as calling event.preventDefault() in your event handler or using the {{action}} modifier like this:

<a href="/" {{action this.someAction preventDefault=true}}>Click me</a>
You can’t perform that action at this time.