通过native select元素更新belongsTo关系

时间:2016-07-28 08:51:04

标签: javascript ember.js

我一直在尝试将Brenna O'Brien的Ember Conf 2016演讲<select>ing Good Ember Patterns的详细信息合并到一个项目中,它正在为简单属性工作(在下面的示例中names是一个数组字符串和model.nameattr( "string" )):

<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>

但是,当它应用于belongsTo关系和模型数组时:

控制器

import Ember from 'ember';

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

模板

<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>

这失败了;关系值已修改,但未设置为有效标题。从某些分析来看,似乎title模型在HTMLBars处理时或在设置为option.value时被字符串化,并且当关系不被转换回来时(不能?)已经确定了。

我目前通过向控制器添加操作来解决它(Ember-Twiddle):

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

并修改模板以调用它:

<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>

然而,我需要为这个想要以这种方式更新的关系创建一个函数。

有没有办法在不调用中间函数或使用附加组件的情况下直接从模板设置belongsTo关系? (如果没有,那么是否有解决这个问题的DRY方法?)

2 个答案:

答案 0 :(得分:2)

不幸的是,在我们拥有可路由组件之前,如果没有从组件发送操作,则无法执行此操作。幸运的是,我们有ember-route-action-helper来帮助我们,这可以作为可路由组件的垫片。 (https://github.com/DockYard/ember-route-action-helper) - 我知道你说你想避免附加组件,但这是目前唯一可用的“不涉及在组件中定义动作的解决方案”(据我所知)。此外,它通常是一个非常有用的附加组件。我正在将它用于此用例和其他用例。额外奖励:当可路由组件出现故障时,您不必进行任何重构。无论如何,这就是我解决这个问题的方法:

您可以在路线上指定操作,并使用Mixin for DRY。(而不是Mixin,您也可以只是扩展Route并从中继承,或者您可以重新打开Route。会反对重新开启路线,因为你不太可能在每条路线上都需要这个动作。避免臃肿。)

此Mixin假定您的模型属性及其引用的belongsTo模型将始终具有相同的名称,因此仅使用一个变量:property。如果不是这种情况,您需要将另一个参数添加(并传递)到setBelongsTo(),并指定用于set()peekRecord()的参数。

经过测试并适用于ember-cli: 2.13.2

选项1:原生选择方法

注意:ember-route-action-helper加载项是必需的

// 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>

选项2:ember-power-select方法

注意:ember-route-action-helper加载项是必需的

如果使用ember-power-selecthttps://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}}

编辑1: OP使用ember-truth-helpers加载项来设置所选选项。 (或者OP为eq创建了自己的帮助器。)这里的第一个解决方案也使用了这个附加组件。

答案 1 :(得分:1)

经过几次尝试并找到the documentation for currying action arguments(这似乎是为了通过value=属性设置其中一个动作时有多个参数的必要条件),这是一个干燥的解决方案:< / p>

<强>组件

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

<强>模板

<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>

(但是,我仍然在寻找一种不涉及在组件中定义操作的解决方案。)