Definition
Attribute
Attribut-Zuweisungen werden immer ohne Anführungszeichen geschrieben.
<img class="foo" src={{logoUrl}} alt={{logoAlt}}>
(mut)1
Die (mut) Closure-Action kann verwendet werden um Werte direkt, ohne Umweg über einen eigenen Action-Handler im Controller zu speichern.
Handler
Event Handler
Event-Handler für Komponenten
Handelt es sich bei der Ember-Komponente um ein einfaches HTML-Element, können dessen Events direkt über das component.js abgehandelt werden.
import Ember from 'ember'; export default Ember.Component.extend({ tagName: 'button', // No action is needed for component wide event handlers click() { /* ... */ } });
Prevent Bubbling
Wird in einem Event-Callback der Return-Value auf false gesetzt, bubbelt der Event nicht weiter dem DOM entlang.
import Ember from 'ember'; export default Ember.Component.extend({ tagName: 'button', click() { console.info('childComponent: click'); // Stop bubbling by returning false (omiting return will not work) return false; } });
import Ember from 'ember'; export default Ember.Component.extend({ tagName: 'form', // click() will never be called, since the bubbling was chanceled on child component click() { console.info('parentComponent: click'); } });
Action Handler
Actions sind eine Sammlug von Methoden, welche durch Benutzer-Interaktion oder Subkomponenten ausgelösst werden.2
Action im “Element-Space”
We have to start by explaining that the {{action}} helper is overloaded and, depending on which context it is used in, it does entirely different things.3
<button {{action "sayHi" <preventDefault=false> <bubble=false> <on="event">}}>Salute</button>
Action als Closure
As a real world example, an {{async-button action=(action “submit”)}} will invoke the action and that action can return a promise. Thanks to having access to that promise, the button can then change to a “loading” state while that returned promise is pending.4
Best Practise
Mit der nachfolgenden Methode kann ein Event von der kleinsten, verschachtelten Komponente bis zum View-Kontroller durchgeschlauft werden. Optional lassen sich sogar Fallback-Handler definieren.
view
<!-- The action clickHandler will become this.clickHandler on parent-component --> {{parent-component clickHandler=(action "clickHandler") }}
actions: { clickHandler() { console.info('controller 2: click'); } }
parent-component
<!-- The action clickHandler will become this.clickHandler on child-component --> {{child-component clickHandler=(action "clickHandler")}}
export default Ember.Component.extend({ actions: { clickHandler(event) { console.log('Parent component', event); // OR redirect to parent handler (use if(this.clickHandler){} if optional) this.get('clickHandler')(...arguments); } } });
child-component
<!-- Note the double quotes, which will force ember to search the action within 'actions' --> <button onclick={{action "clickHandler"}}></button>
export default Ember.Component.extend({ actions: { // This action is called by template, since onclick uses a string reference clickHandler() { // Call model method, which should be replaced by parent component this.get('clickHandler')(...arguments); } }, // This is a fallback action, which will be called, if no clickHandler callback was defined by parent component // This is actually not needed, since there will be an error anyway if no clickHandler was defined! clickHandler() { throw new Error('clickHandler must be provided!!'); } });
Good Reads
- https://spin.atomicobject.com/2016/06/25/emberjs-closure-actions/
- http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/
- http://alexdiliberto.com/posts/ember-closure-actions/
Target auslesen
// Get bare element var target = this.get('element'); // Get jQuery selector of element var $target = this.$();
Target Attribut auslesen
<input type="text" onchange={{action "logArgs" value="target.value"}}> <!-- Logs the value of the input (e.target.input) -->
Event Studie
Fall 1
<li draggable="true" ondragstart={{action "dragStart"}}>Foo</li>
import Ember from 'ember'; export default Ember.Component.extend({ actions: { dragStart(event) { /* event is defined (non jQuery) */ } } });
Fall 2
<li draggable="true" {{action "dragStart" on="dragStart"}}>Foo</li>
import Ember from 'ember'; export default Ember.Component.extend({ actions: { dragStart(event) { /* event is NOT defined */ } } });
Fall 3
<li draggable="true" {{action dragStart on="dragStart"}}>Foo</li>
import Ember from 'ember'; export default Ember.Component.extend({ dragStart(event) { /* Handler gets called twice!! */ /* 1. Call: event is NOT defined */ /* 2. Call: event is defined (jQuery) */ } });
Fall 4
<li draggable="true">Foo</li>
import Ember from 'ember'; export default Ember.Component.extend({ dragStart(event) { /* event is defined (jQuery) */ } });
- http://balinterdi.com/2015/08/29/how-to-do-a-select-dropdown-in-ember-20.html [↩]
- https://guides.emberjs.com/v2.6.0/components/triggering-changes-with-actions/#toc_implementing-the-action [↩]
- http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/ [↩]
- ((http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/ [↩]