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

ACHTUNG: Standard-Events werden von Ember automatisch an das gleichnamige Attribut des Models gebunden. onClick ruft also click auf. Wird der Event auf dem Element zusätzlich über onclick={{action “click”}} gebunden, kommt es zu einem doppelten Aufruf!

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

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) */
  }
});

 

  1. http://balinterdi.com/2015/08/29/how-to-do-a-select-dropdown-in-ember-20.html []
  2. https://guides.emberjs.com/v2.6.0/components/triggering-changes-with-actions/#toc_implementing-the-action []
  3. http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/ []
  4. ((http://miguelcamba.com/blog/2016/01/24/ember-closure-actions-in-depth/ []

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.