2016-07-28 12 views
1

ich versucht habe, Details von Brenna O'Brien ‚s <select>ing Good Ember Patterns in ein Projekt Ember Conf 2016 Gespräch zu übernehmen und es funktioniert für einfache Attribute (im Beispiel unten names ist ein Array von Strings und model.name ist ein attr("string")):aktualisieren belongsTo Beziehung über native select-Element

<select onchange={{action (mut model.name) value="target.value"}}> 
    {{#each names as |name|}} 
    <option value={{name}} selected={{eq name model.name}}>{{name}}</option> 
    {{/each}} 
</select> 

wenn jedoch diese Beziehung auf eine belongsTo angelegt wird, und eine Reihe von Modellen:

Regler:

import Ember from 'ember'; 

export default Ember.Controller.extend({ 
    titles: null, 
    init(){ 
    this.set("titles", this.store.peekAll("title")); 
    } 
}); 

Vorlage:

<select onchange={{action (mut model.title) value="target.value"}}> 
    {{#each titles as |title|}} 
    <option value={{title}} selected={{eq title.id model.title.id}}> 
     {{title.description}} 
    </option> 
    {{/each}} 
</select> 

Dies scheitert; Der Beziehungswert ist geändert, aber er ist nicht auf einen gültigen Titel festgelegt. Aus einer Analyse scheint, dass das title-Modell entweder angegeben wird, wenn es von HTMLBars behandelt wird, oder wenn es als option.value festgelegt ist, und das (nicht?) Wird zurück konvertiert, wenn die Beziehung festgelegt ist.

Ich habe zur Zeit löste es (Ember-Twiddle) durch eine Aktion der Steuerung hinzu:

actions: { 
    title(id){ 
    this.set('model.title', this.store.peekRecord("title", id)); 
    } 
} 

und Modifizieren der Vorlage dieses zu nennen:

<select onchange={{action "title" value="target.value"}}> 
    {{#each titles as |title|}} 
    <option value={{title.id}} selected={{eq title.id model.title.id}}> 
     {{title.description}} 
    </option> 
    {{/each}} 
</select> 

Allerdings muss ich dann ein erstellen Funktion für jede Beziehung, die ich auf diese Weise aktualisieren möchte.

Gibt es eine Möglichkeit, eine belongsTo Beziehung direkt aus der Vorlage festzulegen, ohne eine Zwischenfunktion aufzurufen oder auf Add-Ons zurückzugreifen? (Wenn nicht, dann ist es ein trockenes Verfahren, dies zu lösen?)

Antwort

1

Nach mehreren Versuchen und der Suche nach the documentation for currying action arguments (was für eine Aktion mehr Argumente zu haben, als notwendig erscheint, wenn einer von ihnen über das value= Attribut gesetzt) ​​ist hier eine DRY-er Lösung:

Komponente:

actions: { 
    updateValue(attr, model, id){ 
    this.set(attr, this.store.peekRecord(model, id)); 
    } 
} 

Vorlage:

<select onchange={{action (action "updateValue" "model.title" "title") value="target.value"}}> 
    {{#each titles as |title|}} 
    <option value={{title.id}} selected={{eq title.id model.title.id}}> 
     {{title.description}} 
    </option> 
    {{/each}} 
</select> 

(aber ich bin noch auf der Suche nach einer Lösung, die nicht in der Komponente Aktionen definieren, beinhaltet.)

2

Leider, bis wir routbaren Komponenten haben, gibt es keine Möglichkeit, dies zu tun, ohne eine Aktion mehr senden die Komponente. Zum Glück haben wir ember-route-action-helper, um uns zu helfen, und dies fungiert als eine Art Shim für routingfähige Komponenten. (https://github.com/DockYard/ember-route-action-helper) - Ich weiß, du hast gesagt, du wolltest Add-ons vermeiden, aber dies ist die einzige "Lösung, die nicht die Definition von Aktionen in der Komponente umfasst", die zu diesem Zeitpunkt verfügbar ist (soweit ich weiß). Außerdem ist es ein sehr hilfreiches Add-on im Allgemeinen. Ich benutze es für diesen Anwendungsfall und andere. Bonus: Wenn die routingfähigen Komponenten Länder haben, müssen Sie eigentlich kein Refactoring durchführen.Wie auch immer, so habe ich dieses Problem gelöst:

Sie können die Aktion auf der Route angeben und ein Mixin für DRY verwenden. (Anstatt eines Mixins könnten Sie auch einfach Route verlängern und davon erben, oder Sie könnten Route wieder öffnen. Ich wäre dagegen, die Route wieder zu öffnen, da Sie diese Aktion wahrscheinlich nicht auf jeder einzelnen Route benötigen. Vermeiden Sie Blähungen.)

Dieser Mixin setzt voraus, dass Ihre Modelleigenschaft und das zu referenzierende belongTo-Modell immer den gleichen Namen haben und daher nur eine Variable verwenden: property. Wenn dies nicht der Fall ist, müssen Sie einen weiteren Parameter zu setBelongsTo() hinzufügen (und übergeben) und angeben, welcher Parameter für set() und peekRecord() verwendet wird.

geprüft und Arbeiten auf ember-cli: 2.13.2

Option 1: Gebürtiger Methode auswählen

Anmerkung: ember-route-action-helper Add-on erforderlich ist

// mixins/my-mixin.js 

import Ember from 'ember'; 

export default Ember.Mixin.create({ 
    actions: { 
    setBelongsTo(model, property, value) { 
     this.get('controller').get(model).set(property, this.store.peekRecord(property, value)); 
    } 
    } 
}); 
// routes/my-route.js 

import Ember from 'ember'; 
import SetBelongsToMixin from 'myApp/mixins/set-belongs-to'; 

export default Ember.Route.extend(SetBelongsToMixin, { 
    model() { 
    return this.get('store')find(...); 
    } 
}); 
// templates/my-route.hbs 

<select onchange={{action (route-action 'setBelongsTo' 'model' 'title') value="target.value"}}> 
    {{#each titles as |title|}} 
    <option value={{title.id}} selected={{eq title.id model.title.id}}> 
     {{title.description}} 
    </option> 
    {{/each}} 
</select> 

Option 2: ember-power-select Methode

Anmerkung: ember-route-action-helper Add-on erforderlich ist

einige geringfügige Unterschiede bei Verwendung von ember-power-select (https://github.com/cibernox/ember-power-select)

// mixins/my-mixin.js 

import Ember from 'ember'; 

export default Ember.Mixin.create({ 
    actions: { 
    setBelongsTo(model, property, value) { 
     this.get('controller').get(model).set(property, value); 
    } 
    } 
}); 
// routes/my-route.js 

import Ember from 'ember'; 
import SetBelongsToMixin from 'myApp/mixins/set-belongs-to'; 

export default Ember.Route.extend(SetBelongsToMixin, { 
    model() { 
    return this.get('store')find(...); 
    } 
}); 
// templates/my-route.hbs 

{{#power-select 
    options=titles 
    selected=model.title 
    onchange=(action (route-action 'setBelongsTo' 'model' 'title')) 
    as |title| 
}} 
    {{title.description}} 
{{/power-select}} 

Edit 1: Die OP nutzt ember-truth-helpers Add-on die gewählte Option einzustellen. (Oder OP hat einen eigenen Helper für eq erstellt.) Die erste Lösung verwendet auch dieses Add-On.

Verwandte Themen