All Projects → buschtoens → ember-event-helpers

buschtoens / ember-event-helpers

Licence: MIT license
Complimentary event template helpers to the {{on}} modifier

Programming Languages

javascript
184084 projects - #8 most used programming language
HTML
75241 projects
Handlebars
879 projects

Projects that are alternatives of or similar to ember-event-helpers

ember-render-helpers
Complimentary render template helpers to the render modifiers
Stars: ✭ 19 (-42.42%)
Mutual labels:  ember, emberjs, ember-addon, ember-template-helper, ember-helper
Ember Accessibility
An EmberJS addon to help identify accessibility violations during development
Stars: ✭ 29 (-12.12%)
Mutual labels:  ember, emberjs, ember-addon
ember-link
Link primitive to pass around self-contained route references. It's {{link-to}}, but better!
Stars: ✭ 50 (+51.52%)
Mutual labels:  ember, emberjs, ember-addon
Docfy
Build fully personalized documentation sites; write content and demos in Markdown.
Stars: ✭ 48 (+45.45%)
Mutual labels:  ember, emberjs, ember-addon
ember-best-language
🏳 A FastBoot-enabled addon to detect the best language for your user.
Stars: ✭ 18 (-45.45%)
Mutual labels:  ember, emberjs, ember-addon
ember-deep-tracked
Deep auto-tracking for when you just don't care, and want things to work (at the cost of performance in some situtations)
Stars: ✭ 20 (-39.39%)
Mutual labels:  ember, emberjs, ember-addon
Ember Apollo Client
🚀 An ember-cli addon for Apollo Client and GraphQL
Stars: ✭ 257 (+678.79%)
Mutual labels:  ember, emberjs, ember-addon
ember-on-modifier
Implements the `{{on eventName this.someAction}}` element modifier from https://github.com/emberjs/rfcs/blob/master/text/0471-on-modifier.md
Stars: ✭ 37 (+12.12%)
Mutual labels:  ember, emberjs, ember-addon
Ember Cli Bundle Analyzer
Analyze the size and contents of your Ember app's bundles
Stars: ✭ 78 (+136.36%)
Mutual labels:  ember, emberjs, ember-addon
Ember Styleguide
This is a UI addon that intends to help standardize the Ember family of websites and make it easier to make the Ember website an Ember app.
Stars: ✭ 69 (+109.09%)
Mutual labels:  ember, emberjs, ember-addon
ember-cli-g-maps
Deprecated Google Maps Addon
Stars: ✭ 58 (+75.76%)
Mutual labels:  ember, emberjs, ember-addon
ember-foxy-forms
Ember Addon for Making Foxy Forms
Stars: ✭ 27 (-18.18%)
Mutual labels:  ember, emberjs, ember-addon
ember-credit-card
"make your credit card form dreamy in one line of code"
Stars: ✭ 89 (+169.7%)
Mutual labels:  ember, emberjs, ember-addon
ember-gridstack
Ember components to build drag-and-drop multi-column grids powered by gridstack.js
Stars: ✭ 31 (-6.06%)
Mutual labels:  ember, emberjs, ember-addon
ember-headlessui
gavinjoyce.github.io/ember-headlessui/
Stars: ✭ 76 (+130.3%)
Mutual labels:  ember, emberjs, ember-addon
glimmer-apollo
Ember and Glimmer integration for Apollo Client.
Stars: ✭ 32 (-3.03%)
Mutual labels:  ember, emberjs, ember-addon
ember-shadow-dom
Write templates for your components inside of a Shadow DOM root.
Stars: ✭ 26 (-21.21%)
Mutual labels:  ember, emberjs, ember-addon
ember-changeset-conditional-validations
Conditional validations for ember-changeset-validations
Stars: ✭ 26 (-21.21%)
Mutual labels:  ember, emberjs, ember-addon
Ember Cli Foundation 6 Sass
Stars: ✭ 65 (+96.97%)
Mutual labels:  ember, emberjs, ember-addon
Ember Cli Addon Docs
Easy, beautiful docs for your OSS Ember addons
Stars: ✭ 162 (+390.91%)
Mutual labels:  ember, emberjs, ember-addon

ember-event-helpers

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

Complimentary template helpers to be used with the {{on}} element modifier specified by RFC #471 "{{on}} modifier".

Installation

ember install ember-event-helpers

If you are below Ember 3.10, you'll also want to install the {{on}} modifier polyfill:

ember install ember-on-modifier

Compatibility

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

Usage

👉 For usage information on {{on}} itself, refer to the RFC or polyfill documentation.

Template Helpers

Template Helper Event method
(prevent-default fn) event.preventDefault()
(stop-propagation fn) event.stopPropagation()
(stop-immediate-propagation fn) stopImmediatePropagation

All three template helpers return a function that, when invoked, will call the associated Event method on the first argument. The helper themselves also take an optional fn argument, which is a function that will be called synchronously afterwards with all input arguments of the returned function. The return value of fn is passed through.

Sounds complicated? Let's see some examples instead! 😅

(prevent-default)

Calls event.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.

<label>
  <input type="checkbox" {{on "click" this.onClick}}>
  Click me baby, one more time!
</label>
<label>
  <input type="checkbox" {{on "click" (prevent-default this.onClick)}}>
  Can't touch this!
</label>
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 is used to bind the onClick method's this context to the component instance. This is not required here, since this is not accessed, but in order to not break with patterns, we still do it here.

Using the old {{action}} modifier you would express the same thing like this:

<label>
  <input type="checkbox" {{action this.onClick on="click"}}>
  Click me baby, one more time!
</label>
<label>
  <input type="checkbox" {{action this.onClick on="click" preventDefault=true}}>
  Can't touch this!
</label>

(stop-propagation)

Calls event.stopPropagation().

Stops further propagation of the current event in the capturing phase (down the DOM) and bubbling phase (up the DOM).

<div class="outer" {{on "click" this.onOuterClick}}>
  <div class="inner-a" {{on "click" this.onInnerClick}}>
    I bubble.
  </div>
  <div class="inner-b" {{on "click" (stop-propagation this.onInnerClick)}}>
   I don't bubble.
  </div>
</div>
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 and use (stop-propagation) with it, the event propagation will already be stopped in the capture phase ("down the DOM").

<div class="outer" {{on "click" (stop-propagation this.onOuterClick)}}>
  <div class="inner" {{on "click" this.onInnerClick}}>
    My listener never gets called.
  </div>
</div>

Clicking .inner will only print:

outer

(stop-immediate-propagation)

⚠️ Not implemented yet.

Calls 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 propagation vertically, so further down the DOM (capture phase) or back up the DOM (bubble phase). stopImmediatePropagation 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.

<div class="outer" {{on "click" this.onOuterClick}}>
  <button {{on "click" (stop-propagation this.onInnerClickA)}} {{on "click" this.onInnerClickB}}>
    Both my listeners get called.
  </button>
  <button {{on "click" (stop-immediate-propagation this.onInnerClickA)}} {{on "click" this.onInnerClickB}}>
    Only my first listener gets called.
  </button>
</div>
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 listener is not called. The .outer listener is also not called.

Tips & Tricks

Currying / Partial Application

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

{{#each this.users as |user|}}
  <button {{on "click" (prevent-default (fn this.deleteUser user))}}>
    Delete {{user.name}}
  </button>
{{/each}}

Combining Helpers

You can nest the helpers (recommended):

<button {{on "click" (prevent-default (stop-propagation this.onClick))}}>
  Click me
</button>

Or register additional "void" helpers, since the fn argument is optional:

<button
  {{on "click" (prevent-default)}}
  {{on "click" (stop-propagation)}}
  {{on "click" this.onClick))}}
>
  Click me
</button>

Alternatively you could even use (queue) from ember-composable-helpers.

<button {{on "click" (queue (prevent-default) (stop-propagation) this.onClick)}}>
  Click me
</button>

Getting the event.target.value

With the {{action}} modifier / helper, you used to be able to conveniently access event.target.value (or any other property thereof), like so:

<button onclick={{action this.onClick value="target.value"}}>
  Click me
</button>

You can still easily do this with (pick) from ember-composable-helpers.

<button {{on "click" (pick "target.value" this.onClick)}}>
  Click me
</button>
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].