Complimentary event template helpers to the {{on}} modifier
npm install ember-event-helpers








Complimentary template helpers to be used with the {{on}} element modifier
specified by [RFC #471 "{{on}} modifier"][rfc].
[rfc]: https://emberjs.github.io/rfcs/0471-on-modifier.html
```
ember install ember-event-helpers
If you are below Ember 3.10, you'll also want to install the
[{{on}} modifier polyfill][ember-on-modifier]:
``
ember install ember-on-modifier
[ember-on-modifier]: https://github.com/buschtoens/ember-on-modifier
#### Compatibility
- Ember.js v2.18 or above
- ember-cli v2.13 or above
| Template Helper | Event method |(prevent-default fn)
|----------------------------------------------------------------------|----------------------------------------------------------|
| | [event.preventDefault()][e-preventdefault] |(stop-propagation fn
| | [event.stopPropagation()][e-stoppropagation] |(stop-immediate-propagation fn)
| | [stopImmediatePropagation][e-stopimmediatepropagation] |
[e-preventdefault]: https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
[e-stoppropagation]: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
[e-stopimmediatepropagation]: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation
> ๐ For usage information on {{on}} itself, refer to the [RFC][rfc] or
> [polyfill documentation][ember-on-modifier].
All three template helpers return a function that, when invoked, will call the
associated Event method on the first argument. The helper themselves also takefn
an optional argument, which is a function that will be called synchronouslyfn
afterwards with all input arguments of the returned function. The return value
of is passed through.
Sounds complicated? Let's see some examples instead! ๐
#### (prevent-default)
Calls [event.preventDefault()][e-preventdefault].
Prevent the user agent from performing the default action, like toggling a
checkbox, when it is clicked. The event continues to propagate as usual.
`hbs`
`ts
import Component from '@ember/component';
import { action } from '@ember/object';
export default class CheckboxesComponent extends Component {
@action
onClick(event: MouseEvent) {
if (event.defaultPrevented) {
console.log('Checkbox will not be toggled.');
} else {
console.log('Checkbox will be toggled.');
}
}
}
`
> ๐ The [@action decorator][@action] is used to bind the onClick method'sthis
> context to the component instance. This is not required here, sincethis
> is not accessed, but in order to not break with patterns, we still do
> it here.
[@action]: https://github.com/emberjs/rfcs/blob/master/text/0408-decorators.md#method-binding
Using the old [{{action}} modifier][action-event-propagation] you would
express the same thing like this:
`hbs`
[action-event-propagation]: https://www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/action?anchor=action#event-propagation
#### (stop-propagation)
Calls [event.stopPropagation()][e-stoppropagation].
Stops further propagation of the current event in the capturing phase (down the
DOM) and bubbling phase (up the DOM).
`hbs`
I bubble.
I don't bubble.
`ts
import Component from '@ember/component';
import { action } from '@ember/object';
export default class BubbleGumComponent extends Component {
@action
onOuterClick(event: MouseEvent) {
console.log('outer');
}
@action
onInnerClick(event: MouseEvent) {
console.log('inner');
}
}
`
Clicking .inner-a will print:
``
inner
outer
Clicking .inner-b will only print:
``
inner
If you enable the [capture event option][capture] and use (stop-propagation)
with it, the event propagation will already be stopped in the capture phase
("down the DOM").
[capture]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters
`hbs`
My listener never gets called.
Clicking .inner will only print:
``
outer
#### (stop-immediate-propagation)
> โ ๏ธ Not implemented yet.
Calls [stopImmediatePropagation][e-stopimmediatepropagation].
Like stopPropagation, but additionally even stopping any further listeners on
the _current_ element in the bubbling / capturing phase to be called.
> ๐ Imagine it like this: stopPropagation only stops further propagationstopImmediatePropagation
> _vertically_, so further down the DOM (capture phase) or back up the DOM
> (bubble phase). additionally prevents any further
> _horizontal_ propagation, so any further listeners on the same element will
> not be called.
In practice, you will probably never need this helper.
`hbs`
`ts
import Component from '@ember/component';
import { action } from '@ember/object';
export default class BubbleGumComponent extends Component {
@action
onOuterClick(event: MouseEvent) {
console.log('outer');
}
@action
onInnerClickA(event: MouseEvent) {
console.log('inner A');
}
@action
onInnerClickB(event: MouseEvent) {
console.log('inner B');
}
}
`
Clicking the first button prints:
``
inner A
inner B
The listeners are executed in the order they were registered in. The listener on
.outer is not called, since the first listener uses (stop-propagation), so
there is no bubbling.
Clicking the second button prints:
``
inner A
Since the first listener uses (stop-immediate-propagation), the second.outer
listener is not called. The listener is also not called.
If you want to curry the function call / partially apply arguments, you can do
so using the [{{fn}} helper][fn-helper]:
[fn-helper]: https://github.com/emberjs/rfcs/blob/master/text/0470-fn-helper.md
`hbs`
{{#each this.users as |user|}}
{{/each}}
You can nest the helpers:
`hbs`
Or register additional "void" helpers, since the fn argument is optional:
`hbs``
{{on "click" (prevent-default)}}
{{on "click" (stop-propagation)}}
{{on "click" this.onClick))}}
>
Click me