Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Events in Ember
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
stopPropagationAndLog(event) {
// This action has access to the DOM event and can call
// stopPropagation on it to prevent the event from bubbling.
event.stopPropagation();
this.get('log')(`clickAttribute w/ stopPropagation of ${this.get('parentName')}`);
}
}
});
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
stopPropagationAndLog(event) {
// This action has access to the DOM event and can call
// stopPropagation on it to prevent the event from bubbling.
event.stopPropagation();
this.get('log')(`onClick w/ stopPropagation of ${this.get('parentName')}`);
}
}
});
import Ember from 'ember';
export default Ember.Component.extend({
click() {
this.sendAction();
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
logs: [],
actions: {
log(name) {
this.get('logs').pushObject(name);
},
clearLogs() {
this.set('logs', [])
}
}
});
body {
--padding-xsmall: 4px;
--padding-small: 8px;
--padding-medium: 16px;
--padding-large: 32px;
--color-text--dom: #F1EFF3;
--color-lightest--dom: #AE9FBB;
--color-light--dom: #6C5084;
--color-medium--dom: #350F57;
--color-dark--dom: #140620;
--color-text--ember: #080F10;
--color-lightest--ember: #C3F0F1;
--color-light--ember: #83D0D3;
--color-medium--ember: #56A3A6;
--color-dark--ember: #1D3738;
margin: var(--padding-medium);
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
pre {
font-size: 12px;
}
.wrapper {
display: flex;
}
.example-column {
flex: 1 0 auto;
max-width: 75%;
padding: var(--padding-xsmall);
}
.log-column {
flex: 0 1 25%;
padding: var(--padding-xsmall);
}
.log-content {
position: fixed;
top: 0;
padding: var(--padding-medium) 0;
}
.log-line {
padding: var(--padding-small) 0;
}
.helper {
padding: var(--padding-xsmall);
}
.parent {
padding: var(--padding-medium);
margin: var(--padding-large) 0;
max-width: 400px;
}
.parent--dom,
.helper--dom {
background-color: var(--color-medium--dom);
border: 1px solid var(--color-dark--dom);
color: var(--color-text--dom);
}
.parent--ember,
.helper--ember {
background-color: var(--color-medium--ember);
border: 1px solid var(--color-dark--ember);
color: var(--color-text--ember);
}
.child {
padding: var(--padding-small);
margin: var(--padding-small) 0;
cursor: pointer;
}
.child--dom,
.parent--dom .child--default {
background-color: var(--color-light--dom);
border: 1px solid var(--color-dark--dom);
color: var(--color-text--dom);
}
.child--ember,
.parent--ember .child--default {
background-color: var(--color-light--ember);
border: 1px solid var(--color-dark--ember);
color: var(--color-text--ember);
}
.child--invalid {
font-size: 10pt;
cursor: default;
}
.child--dom.child--invalid {
background-color: var(--color-lightest--dom);
}
.child--ember.child--invalid {
background-color: var(--color-lightest--ember);
}
<div class="wrapper">
<div class="example-column">
<strong>Events in Ember</strong>
<p><span class="helper helper--dom">DOM Event Listeners</span> use the standard event APIs that browsers implement to listen for and respond to events like clicks.</p>
<p><span class="helper helper--ember">Ember Actions</span> are implemented by Ember and are an abstraction built on top of DOM events.</p>
<p>You can use both in Ember, but they have slightly different behavior and ordering!</p>
<p>There are three main ways of attaching handlers for click events in Ember. Try them out below!</p>
<ul>
<li>
<strong>click Component Attribute:</strong>
<pre>&#123;&#123;my-component click=(action "handleClick")&#125;&#125;</pre>
</li>
<li>
<strong>Element Modifier:</strong>
<pre>&lt;div &#123;&#123;action "handleClick"&#125;&#125;&gt;</pre>
</li>
<li>
<strong>onClick HTML Attribute:</strong>
<pre>&lt;div onClick=&#123;&#123;action "handleClick"&#125;&#125;&gt;</pre>
</li>
</ul>
<p>All of these methods can be used to handle other DOM events too (like "submit" or "mouseover").</p>
{{example-column log=(action "log")}}
</div>
<div class="log-column">
<div class="log-content">
<strong>Event Log:</strong> (<a href="" {{action "clearLogs"}}>clear</a>)
<ol>
{{#each logs as |log|}}
<li class="log-line">{{log}}</li>
{{/each}}
</ol>
</div>
</div>
</div>
{{!-- It really doesn't matter what's in this component, or whether you use it in block mode or not. You can attach click handlers to any component by passing an action to `click`.--}}
{{yield}}
{{#block-component class="child child--ember"
click=(action log (concat "clickAttribute child of " parentName))}}
Child with <strong>click Attribute</strong>
{{/block-component}}
{{#block-component class="child child--ember child--invalid"
click=(action log (concat "clickAttribute child (bubbles=false) of " parentName) bubbles=false)}}
<!-- See this GitHub issue for more context: https://github.com/emberjs/ember.js/issues/12632#issuecomment-158657664 -->
Setting <strong>bubbles=false</strong> on a closure action doesn't have any effect, as it is not currently a supported hash argument.
{{/block-component}}
{{#block-component class="child child--ember"
click=(action "stopPropagationAndLog")}}
Child with <strong>click Attribute, event.stopPropagation()</strong>
{{/block-component}}
<div class="child child--ember"
{{action log (concat "elementModifier child of " parentName)}}>
Child with <strong>Element Modifier</strong>
</div>
<div class="child child--ember"
{{action log (concat "elementModifier child (bubbles=false) of " parentName) bubbles=false}}>
Child with <strong>Element Modifier, bubbles=false</strong>
</div>
<div class="child child--ember child--invalid"
{{action log (concat "elementModifier child (can't call stopPropagation) of " parentName)}}>
Element Modifier does not have access to DOM event, and cannot use <strong>event.stopPropagation()</strong>
</div>
<div class="child child--default">
Child
</div>
{{yield (hash
element-modifier=(component "child-elements/element-modifier"
parentName=parentName
log=log)
click-attribute=(component "child-elements/click-attribute"
parentName=parentName
log=log)
on-click=(component "child-elements/on-click"
parentName=parentName
log=log)
)}}
<div class="child child--dom"
onClick={{action log (concat "onClick child of " parentName)}}>
Child with <strong>onClick</strong>
</div>
<div class="child child--dom child--invalid"
onClick={{action log (concat "onClick child (bubbles=false) of " parentName) bubbles=false}}>
Setting <strong>bubbles=false</strong> on an onClick action has no effect, as that property modifies Ember events not DOM events.
</div>
<div class="child child--dom"
onClick={{action "stopPropagationAndLog"}}>
Child with <strong>onClick, event.stopPropagation()</strong>
</div>
{{!-- CLICK COMPONENT ATTRIBUTE --}}
{{#block-component class="parent parent--ember" click=(action log "clickAttribute")}}
{{example-handler options=(hash
name="click Component Attribute"
logName="clickAttribute"
log=log
note="(Similar behavior to Element Modifier.)"
type="Ember"
canAccessDOMEvent="Yes"
exampleCode='{{my-component click=(action "handleClick")}}'
elementModifierNote="Fires <strong>after</strong> Element Modifier actions from children, <strong>unless</strong> the action does not bubble."
clickAttributeNote="Fires <strong>after</strong> click Attribute actions from children, <strong>unless</strong> the action stops propagation."
onClickNote="Fires <strong>after</strong> onClick Attribute actions from children, <strong>even if</strong> the action does not bubble. Does not fire after actions that stop propagation."
)}}
{{/block-component}}
{{!-- ELEMENT MODIFIER --}}
<div class="parent parent--ember" {{action log "elementModifier"}}>
{{example-handler options=(hash
name="Element Modifier"
logName="elementModifier"
log=log
note="(Similar behavior to click Component Attribute.)"
type="Ember"
canAccessDOMEvent="No"
exampleCode='<div {{action "handleClick"}}>'
elementModifierNote="Fires <strong>after</strong> Element Modifier actions from children, <strong>unless</strong> the action does not bubble."
clickAttributeNote="Fires <strong>after</strong> click Attribute actions from children, <strong>unless</strong> the action stops propagation."
onClickNote="Fires <strong>after</strong> onClick Attribute actions from children, <strong>even if</strong> the action does not bubble. Does not fire after actions that stop propagation."
)}}
</div>
{{!-- ONCLICK HTML ATTRIBUTE --}}
<div class="parent parent--dom" onClick={{action log "onClick"}}>
{{example-handler options=(hash
name="onClick HTML Attribute"
logName="onClick"
log=log
type="DOM"
canAccessDOMEvent="Yes"
exampleCode='<div onClick={{action "handleClick"}}>'
elementModifierNote="Fires <strong>before</strong> Element Modifier actions from children, <strong>even if</strong> the action does not bubble."
clickAttributeNote="Fires <strong>before</strong> click Attribute actions from children, <strong>even if</strong> the action stops propagation."
onClickNote="Fires <strong>after</strong> onClick Attribute actions from children, <strong>even if</strong> the action does not bubble. Does not fire after actions that stop propagation."
)}}
</div>
<strong>{{options.name}}</strong>
<small>
{{#if options.note}}
<br>{{options.note}}
{{/if}}
<br>
<br><strong>Type of Event Listener:</strong> {{options.type}}
<br><strong>Access to DOM Event:</strong> {{options.canAccessDOMEvent}}
<br><strong>Example:</strong>
</small>
<pre>{{options.exampleCode}}</pre>
{{#child-elements parentName=options.logName
log=options.log as |children|}}
<p>{{{options.clickAttributeNote}}}</p>
{{children.click-attribute}}
<p>{{{options.elementModifierNote}}}</p>
{{children.element-modifier}}
<p>{{{options.onClickNote}}}</p>
{{children.on-click}}
{{/child-elements}}
{
"version": "0.12.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.12.0",
"ember-template-compiler": "2.12.0",
"ember-testing": "2.12.0"
},
"addons": {
"ember-data": "2.12.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment