如何从Ember中的模板调用控制器功能?

时间:2015-04-09 16:54:34

标签: ember.js

假设我有一个模板,它迭代了一组项目,我想调用一个特定于控制器的项目的函数,而不是模型级别的关注:

{{#each people as |person|}}
  icon name: {{findIconFor(person)}}
{{/each}}

我想在控制器中定义findIconFor,因为这是特定视图的特定内容。

export default Ember.Controller.extend({
  findIconFor: function(person) {
    // figure out which icon to use
  }
);

但这不起作用。模板无法编译。解析错误:期待' STRING',' NUMBER',' ID',' DATA',' INVALID&# 39;

什么是" ember方式"这样做?

3 个答案:

答案 0 :(得分:13)

因为我几乎整天都在类似的问题上花了我的解决方案。

因为Ember由于某种原因只是不允许你直接从模板中运行控制器功能(这很荒谬,并以一些非常愚蠢的方式绑手,我不知道谁在地球上认为这是一个好的想法...)对我来说最有意义的是创建一个通用的自定义帮助器,它允许你从模板运行函数:)这里的问题是你应该总是传递当前范围(“this”变量对那个帮助者。

所以助手可能是这样的:

export default Ember.Helper.helper(function([scope, fn]) {
    let args = arguments[0].slice(2);
    let res = fn.apply(scope, args);
    return res;
});

然后,您可以在控制器中创建要运行的功能,例如:

testFn: function(element){
    return element.get('name');
}

然后在您的模板中,您只需使用自定义帮助程序调用它:

{{#each items as |element|}}
    {{{custom-helper this testFn element}}}
{{/each}}

帮助器的前两个参数应该始终是“this”和要运行的函数的名称,然后您可以根据需要传递多个额外的参数。

编辑:无论如何,每当你认为你需要这样做时,你应该考虑改为创建新组件是否更好(在90%的情况下都是如此)

答案 1 :(得分:8)

我在控制器中使用了计算属性:

iconPeople: Ember.computed('people.@each', function(){
  var that = this;
  return this.get('people').map(function(person){
    return {
      'person': person,
      'icon': that.findIconFor(person)
    };
  });
})

现在,您可以从{{person.icon}}获取图标,从{{person.person.name}}获取名称。您可能希望改进(并且代码未经测试),但这是一般的想法。

答案 2 :(得分:0)

如果图标是与某个人相关联的内容,那么由于该人员是由模型表示的,因此最好将其作为人员模型上的计算属性来实现。你试图将它放入控制器的意图是什么?

// person.js
export default DS.Model.extend({
  icon: function() { return "person-icon-" + this.get('name'); }.property('name')
  ..
};

然后假设peopleperson的数组:

{{#each people as |person|}}
  icon name: {{person.icon}}
{{/each}}

@jnfingerle提供的替代工作(我假设你发现他建议你循环iconPeople),但是创建一个包含对象的新数组似乎需要做很多额外的工作。图标是否依赖于控制器只知道的任何内容?如果没有,正如我所说,为什么计算它的逻辑应该在控制器中呢?

在哪里放东西是一个哲学和偏好的问题。有些人喜欢简单的模型,只包含从服务器下来的字段;其他人在模型中计算状态和中间结果。有些人在控制器中放置了很多东西,而另一些人更喜欢在“服务”中使用更多逻辑的轻量级控制器。就个人而言,我更重要的是模型,更轻的控制器和服务。当然,我并没有声称业务逻辑,或大量数据转换或视图准备应该在模型中。但请记住,模型代表一个对象。如果对象有一些有趣的方面,无论是从服务器上下来还是以某种方式进行计算,对我来说,将它放在模型中是很有意义的。

还要记住,控制器是紧密耦合的路径/控制器/视图连接的一部分。如果您在一个控制器中计算了某些特定于模型的事物,则可能必须将其添加到恰好处理相同模型的其他控制器。然后在你知道它之前,你正在编写控制器mixin,它们在控制器之间共享逻辑,而这些控制器本来就不应该存在于控制器中。

无论如何,你说你的图标来自“不相关的数据存储”。听起来不同寻常。对我来说,这暗示可能是PersonIcon的一个子模型,它是belongsTo模型中的person。您可以使用适合该模型的适配器和序列化程序组合。关于这种方法的好处在于,在创建person模型时,或者当您确实需要图标时(如果您说{{1}),检索图标的所有异步性都将被半神奇地处理。 }})。

但也许你没有使用Ember Data,或者不想解决所有麻烦。在这种情况下,您可以考虑使用路径模型钩子中的图标来装饰此人,利用Ember处理异步模型分辨率的能力,通过执行以下操作:

async: true

其中model: function() { return this.store.find('person') . then(function(people) { return Ember.RSVP.Promise.all(people.map(getIcon)) . then(function(icons) { people.forEach(function(person, i) { person.set('icon') = icons[i]; }); return people; }) ; }) ; } 类似于

getIcon

或者,如果它更干净,你可以将图标内容分解为function getIcon(person) { return new Ember.RSVP.Promise(function(resolve, reject) { $.ajax('http://icon-maker.com?' + person.get('name'), resolve); }); } 钩子:

afterModel

现在,Ember将等待整个承诺的解决,包括获取人员和他们的图标,并在继续之前将图标贴在人们身上。

HTH。