ember-on-modifier
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>