{"id":13806869,"url":"https://github.com/buschtoens/ember-event-helpers","last_synced_at":"2025-04-12T09:27:20.534Z","repository":{"id":34775672,"uuid":"183616285","full_name":"buschtoens/ember-event-helpers","owner":"buschtoens","description":"Complimentary event template helpers to the {{on}} modifier","archived":false,"fork":false,"pushed_at":"2023-12-15T14:51:18.000Z","size":2672,"stargazers_count":36,"open_issues_count":19,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T13:53:41.141Z","etag":null,"topics":["ember","ember-addon","ember-helper","ember-template-helper","emberjs","events"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buschtoens.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-04-26T11:24:59.000Z","updated_at":"2024-06-11T16:11:48.000Z","dependencies_parsed_at":"2024-01-09T05:01:45.195Z","dependency_job_id":"30fab515-4b66-451a-b8b6-f34c7e153e6c","html_url":"https://github.com/buschtoens/ember-event-helpers","commit_stats":{"total_commits":345,"total_committers":8,"mean_commits":43.125,"dds":"0.11014492753623184","last_synced_commit":"757aedf62d832aaa82a8ceb3d85567d6cc324a4a"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buschtoens%2Fember-event-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buschtoens%2Fember-event-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buschtoens%2Fember-event-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buschtoens%2Fember-event-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buschtoens","download_url":"https://codeload.github.com/buschtoens/ember-event-helpers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248545483,"owners_count":21122151,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ember","ember-addon","ember-helper","ember-template-helper","emberjs","events"],"created_at":"2024-08-04T01:01:17.308Z","updated_at":"2025-04-12T09:27:20.513Z","avatar_url":"https://github.com/buschtoens.png","language":"JavaScript","funding_links":[],"categories":["Packages"],"sub_categories":["Helpers"],"readme":"# ember-event-helpers\n\n[![CI](https://github.com/buschtoens/ember-event-helpers/workflows/CI/badge.svg)](https://github.com/buschtoens/ember-event-helpers/actions)\n[![npm version](https://badge.fury.io/js/ember-event-helpers.svg)](http://badge.fury.io/js/ember-event-helpers)\n[![Download Total](https://img.shields.io/npm/dt/ember-event-helpers.svg)](http://badge.fury.io/js/ember-event-helpers)\n[![Ember Observer Score](https://emberobserver.com/badges/ember-event-helpers.svg)](https://emberobserver.com/addons/ember-event-helpers)\n[![Ember Versions](https://img.shields.io/badge/Ember.js%20Versions-%5E2.18%20%7C%7C%20%5E3.0-brightgreen.svg)](https://travis-ci.org/buschtoens/ember-event-helpers)\n[![ember-cli Versions](https://img.shields.io/badge/ember--cli%20Versions-%5E2.13%20%7C%7C%20%5E3.0-brightgreen.svg)](https://travis-ci.org/buschtoens/ember-event-helpers)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![dependencies](https://img.shields.io/david/buschtoens/ember-event-helpers.svg)](https://david-dm.org/buschtoens/ember-event-helpers)\n[![devDependencies](https://img.shields.io/david/dev/buschtoens/ember-event-helpers.svg)](https://david-dm.org/buschtoens/ember-event-helpers)\n\nComplimentary template helpers to be used with the `{{on}}` element modifier\nspecified by [RFC #471 \"`{{on}}` modifier\"][rfc].\n\n[rfc]: https://emberjs.github.io/rfcs/0471-on-modifier.html\n\n## Installation\n\n```\nember install ember-event-helpers\n```\n\nIf you are below Ember 3.10, you'll also want to install the\n[`{{on}}` modifier polyfill][ember-on-modifier]:\n\n```\nember install ember-on-modifier\n```\n\n[ember-on-modifier]: https://github.com/buschtoens/ember-on-modifier\n\n#### Compatibility\n\n- Ember.js v2.18 or above\n- ember-cli v2.13 or above\n\n## Usage\n\n- **[Template Helpers](#template-helpers)**\n  - [`(prevent-default fn)`](#prevent-default)\n  - [`(stop-propagation fn)`](#stop-propagation)\n  - [`(stop-immediate-propagation fn)`](#stop-immediate-propagation)\n- **[Tips \u0026 Tricks](#tips--tricks)**\n  - [Currying / Partial Application](#currying--partial-application)\n  - [Combining Helpers](#combining-helpers)\n  - [Getting the `event.target.value`](#getting-the-eventtargetvalue)\n\n\u003e 👉 For usage information on `{{on}}` itself, refer to the [RFC][rfc] or\n\u003e [polyfill documentation][ember-on-modifier].\n\n### Template Helpers\n\n| Template Helper                                                      | `Event` method                                           |\n|----------------------------------------------------------------------|----------------------------------------------------------|\n| **[`(prevent-default fn)`](#prevent-default)**                       | [`event.preventDefault()`][e-preventdefault]             |\n| **[`(stop-propagation fn)`](#stop-propagation)**                     | [`event.stopPropagation()`][e-stoppropagation]           |\n| **[`(stop-immediate-propagation fn)`](#stop-immediate-propagation)** | [`stopImmediatePropagation`][e-stopimmediatepropagation] |\n\n[e-preventdefault]: https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault\n[e-stoppropagation]: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation\n[e-stopimmediatepropagation]: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation\n\nAll three template helpers return a function that, when invoked, will call the\nassociated `Event` method on the first argument. The helper themselves also take\nan optional `fn` argument, which is a function that will be called synchronously\nafterwards with all input arguments of the returned function. The return value\nof `fn` is passed through.\n\nSounds complicated? Let's see some examples instead! 😅\n\n#### `(prevent-default)`\n\nCalls [`event.preventDefault()`][e-preventdefault].\n\nPrevent the user agent from performing the default action, like toggling a\ncheckbox, when it is clicked. The event continues to propagate as usual.\n\n```hbs\n\u003clabel\u003e\n  \u003cinput type=\"checkbox\" {{on \"click\" this.onClick}}\u003e\n  Click me baby, one more time!\n\u003c/label\u003e\n\u003clabel\u003e\n  \u003cinput type=\"checkbox\" {{on \"click\" (prevent-default this.onClick)}}\u003e\n  Can't touch this!\n\u003c/label\u003e\n```\n\n```ts\nimport Component from '@ember/component';\nimport { action } from '@ember/object';\n\nexport default class CheckboxesComponent extends Component {\n  @action\n  onClick(event: MouseEvent) {\n    if (event.defaultPrevented) {\n      console.log('Checkbox will not be toggled.');\n    } else {\n      console.log('Checkbox will be toggled.');\n    }\n  }\n}\n```\n\n\u003e 👉 The [`@action` decorator][@action] is used to bind the `onClick` method's\n\u003e `this` context to the component instance. This is not required here, since\n\u003e `this` is not accessed, but in order to not break with patterns, we still do\n\u003e it here.\n\n[@action]: https://github.com/emberjs/rfcs/blob/master/text/0408-decorators.md#method-binding\n\nUsing the old [`{{action}}` modifier][action-event-propagation] you would\nexpress the same thing like this:\n\n```hbs\n\u003clabel\u003e\n  \u003cinput type=\"checkbox\" {{action this.onClick on=\"click\"}}\u003e\n  Click me baby, one more time!\n\u003c/label\u003e\n\u003clabel\u003e\n  \u003cinput type=\"checkbox\" {{action this.onClick on=\"click\" preventDefault=true}}\u003e\n  Can't touch this!\n\u003c/label\u003e\n```\n\n[action-event-propagation]: https://www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/action?anchor=action#event-propagation\n\n#### `(stop-propagation)`\n\nCalls [`event.stopPropagation()`][e-stoppropagation].\n\nStops further propagation of the current event in the capturing phase (down the\nDOM) and bubbling phase (up the DOM).\n\n```hbs\n\u003cdiv class=\"outer\" {{on \"click\" this.onOuterClick}}\u003e\n  \u003cdiv class=\"inner-a\" {{on \"click\" this.onInnerClick}}\u003e\n    I bubble.\n  \u003c/div\u003e\n  \u003cdiv class=\"inner-b\" {{on \"click\" (stop-propagation this.onInnerClick)}}\u003e\n   I don't bubble.\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```ts\nimport Component from '@ember/component';\nimport { action } from '@ember/object';\n\nexport default class BubbleGumComponent extends Component {\n  @action\n  onOuterClick(event: MouseEvent) {\n    console.log('outer');\n  }\n\n  @action\n  onInnerClick(event: MouseEvent) {\n    console.log('inner');\n  }\n}\n```\n\nClicking `.inner-a` will print:\n\n```\ninner\nouter\n```\n\nClicking `.inner-b` will only print:\n\n```\ninner\n```\n\nIf you enable the [`capture` event option][capture] and use `(stop-propagation)`\nwith it, the event propagation will already be stopped in the capture phase\n(\"down the DOM\").\n\n[capture]: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters\n\n```hbs\n\u003cdiv class=\"outer\" {{on \"click\" (stop-propagation this.onOuterClick)}}\u003e\n  \u003cdiv class=\"inner\" {{on \"click\" this.onInnerClick}}\u003e\n    My listener never gets called.\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nClicking `.inner` will only print:\n\n```\nouter\n```\n\n#### `(stop-immediate-propagation)`\n\n\u003e ⚠️ Not implemented yet.\n\nCalls [`stopImmediatePropagation`][e-stopimmediatepropagation].\n\nLike `stopPropagation`, but additionally even stopping any further listeners on\nthe _current_ element in the bubbling / capturing phase to be called.\n\n\u003e 👉 Imagine it like this: `stopPropagation` only stops further propagation\n\u003e _vertically_, so further down the DOM (capture phase) or back up the DOM\n\u003e (bubble phase). `stopImmediatePropagation` additionally prevents any further\n\u003e _horizontal_ propagation, so any further listeners on the same element will\n\u003e not be called.\n\nIn practice, you will probably never need this helper.\n\n```hbs\n\u003cdiv class=\"outer\" {{on \"click\" this.onOuterClick}}\u003e\n  \u003cbutton {{on \"click\" (stop-propagation this.onInnerClickA)}} {{on \"click\" this.onInnerClickB}}\u003e\n    Both my listeners get called.\n  \u003c/button\u003e\n  \u003cbutton {{on \"click\" (stop-immediate-propagation this.onInnerClickA)}} {{on \"click\" this.onInnerClickB}}\u003e\n    Only my first listener gets called.\n  \u003c/button\u003e\n\u003c/div\u003e\n```\n\n```ts\nimport Component from '@ember/component';\nimport { action } from '@ember/object';\n\nexport default class BubbleGumComponent extends Component {\n  @action\n  onOuterClick(event: MouseEvent) {\n    console.log('outer');\n  }\n\n  @action\n  onInnerClickA(event: MouseEvent) {\n    console.log('inner A');\n  }\n\n  @action\n  onInnerClickB(event: MouseEvent) {\n    console.log('inner B');\n  }\n}\n```\n\nClicking the first button prints:\n\n```\ninner A\ninner B\n```\n\nThe listeners are executed in the order they were registered in. The listener on\n`.outer` is not called, since the first listener uses `(stop-propagation)`, so\nthere is no bubbling.\n\nClicking the second button prints:\n\n```\ninner A\n```\n\nSince the first listener uses `(stop-immediate-propagation)`, the second\nlistener is not called. The `.outer` listener is also not called.\n\n### Tips \u0026 Tricks\n\n#### Currying / Partial Application\n\nIf you want to curry the function call / partially apply arguments, you can do\nso using the [`{{fn}}` helper][fn-helper]:\n\n[fn-helper]: https://github.com/emberjs/rfcs/blob/master/text/0470-fn-helper.md\n\n```hbs\n{{#each this.users as |user|}}\n  \u003cbutton {{on \"click\" (prevent-default (fn this.deleteUser user))}}\u003e\n    Delete {{user.name}}\n  \u003c/button\u003e\n{{/each}}\n```\n\n#### Combining Helpers\n\nYou can nest the helpers (recommended):\n\n```hbs\n\u003cbutton {{on \"click\" (prevent-default (stop-propagation this.onClick))}}\u003e\n  Click me\n\u003c/button\u003e\n```\n\nOr register additional \"void\" helpers, since the `fn` argument is optional:\n\n```hbs\n\u003cbutton\n  {{on \"click\" (prevent-default)}}\n  {{on \"click\" (stop-propagation)}}\n  {{on \"click\" this.onClick))}}\n\u003e\n  Click me\n\u003c/button\u003e\n```\n\nAlternatively you could even use [`(queue)` from `ember-composable-helpers`][queue].\n\n[queue]: https://github.com/DockYard/ember-composable-helpers#queue\n\n```hbs\n\u003cbutton {{on \"click\" (queue (prevent-default) (stop-propagation) this.onClick)}}\u003e\n  Click me\n\u003c/button\u003e\n```\n\n#### Getting the `event.target.value`\n\nWith the `{{action}}` modifier / helper, you used to be able to conveniently access\n`event.target.value` (or any other property thereof), like so:\n\n```hbs\n\u003cbutton onclick={{action this.onClick value=\"target.value\"}}\u003e\n  Click me\n\u003c/button\u003e\n```\n\nYou can still easily do this with [`(pick)` from `ember-composable-helpers`][pick].\n\n[pick]: https://github.com/DockYard/ember-composable-helpers#pick\n\n```hbs\n\u003cbutton {{on \"click\" (pick \"target.value\" this.onClick)}}\u003e\n  Click me\n\u003c/button\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuschtoens%2Fember-event-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbuschtoens%2Fember-event-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuschtoens%2Fember-event-helpers/lists"}