【问题标题】:Removing an itemController when upgrading to Ember 2.0升级到 Ember 2.0 时删除 itemController
【发布时间】:2015-12-08 11:14:55
【问题描述】:

我正在重写我的应用程序以符合 Ember 2,但在尝试重构 ItemController 时遇到了一个大问题。

目前我有一个 arrayController 有一个项目数组。用户有许多可供选择的用于对显示的数据进行排序的选项。 有些排序直接依赖于控制器上设置的属性(由用户通过模板提供)。为此,我目前声明了一个项目控制器,这意味着我可以创建一个计算属性来计算我需要的排序值。这不能通过模型​​上的 computedProperty 来完成,因为模型不知道已设置的控制器属性。

如何重构它以不使用 itemControllers - 我不知所措。

我将一些代码 sn-ps 放在一起试图解释我的意思。我正在尝试对 itemController 属性 numberOfSelectedFruit 进行排序,每个“人”的值将取决于控制器上的 selectedFruit 属性(从模板中提取)。这是一个愚蠢的例子,但我认为它说明了问题。

我非常感谢任何关于 ember 2 方式的帮助(我也看不出组件如何提供帮助)

// model
APP.Person = DS.Model.extend({
  name: DS.attr('string'),
  // Not proper code, but to show the structure of the fruit field
  fruit: [{type: DS.attr(‘string’), number: DS.attr(‘number’}]
})

// person_controller
APP.PersonItemController = Ember.ObjectController.extend({
  numberOfSelectedFruit: function() {
    var parentController = this.get('parentController');

    var fruitType = parentController.selectedFruit;
    var numberOfFruit = 0;
    this.get(‘fruit’).forEach(function(aFruit) {
      if(aFruit.type === fruitType) {
        numberOfFruit++;
      }
    });
    return numberOfFruit;
  }
})

APP.PersonController = Ember.ArrayController.extend({
  itemController: 'PersonItem',
  sortingOn: 'name',
  selectedFruit: 'orange',
  sortedPeople: Ember.computed.sort('filteredContent', 'sortingOn'),

})

编辑以添加模板代码

模板代码可以像下面这样简单,带有一个选择器来选择“水果”(这将在控制器上设置 selectedFruit 属性。

// person.hbs
<table>
  <tbody>
      {{#each sortedPeople as |person|}}
      <tr>
        <td>{{person.name}} {person.numberOfSelectedFruit}</td>
      </tr>
      {{/each}}
  </tbody>

</table>

【问题讨论】:

  • 请出示您的模板代码。
  • 编辑添加简单的模板代码。它不包括选择排序字段或“fruitType”(来自示例)的所有元素,因为我觉得这只会混淆示例。

标签: ember.js


【解决方案1】:

如前所述,通常您可以使用组件作为您的项目控制器。这非常简单明了,比 itemController 更容易被大多数人理解:

// person.hbs
<table>
  <tbody>
      {{#each sortedPeople as |person|}}
           {{person-item person=person selectedFruit=selectedFruit}}
      {{/each}}
  </tbody>

</table>

// components/person-item.js
import Ember from "ember";

const { computed } = Ember;

export default Ember.Component.extend({
    tagName: 'tr',

    numberOfSelectedFruit: computed('selectedFruit', 'person.fruit.@each.{type,number}', function() {
        const selectedFruit = this.get('selectedFruit');
        return this.get('person.fruit')
            .filter(aFruit => aFruit.type === selectedFruit)
            .map(aFruit => aFruit.number)
            .reduce((previous, current) => previous + current);
    })
});

// templates/components/person-item.hbs

<td>{{person.name}} {{numberOfSelectedFruit}}</td>

但是,您说您希望能够按 numberOfSelectedFruit 对人员进行排序。由于您不再拥有 itemController、ObjectController 或 ArrayController,因此您必须将 numberOfSelectedFruit 计算属性移动到 ObjectProxy,如下所示:

// controllers/person.js
import Ember from "ember";
import PersonProxy from "../models/person-proxy";

export default Ember.Controller.extend({
    // ...

    proxiedPeople: computed('model.[]', function() {
        return this.get('model').map((person) => PersonProxy.create({
            content: person,
            context: this
        }));
    }),

    selectedFruit: 'orange'
    sortedPeople: computed.sort('proxiedPeople', 'sortingOn'),
    sortingOn: ['numberOfSelectedFruit:asc']
});

// models/person-proxy.js
import Ember from "ember";

const { computed } = Ember;

export default Ember.ObjectProxy.create({
    selectedFruit: computed.readOnly('context.selectedFruit')

    numberOfSelectedFruit: computed('selectedFruit', 'fruit.@each.{type,number}', function() {
        const selectedFruit = this.get('selectedFruit');
        return this.get('fruit')
            .filter(aFruit => aFruit.type === selectedFruit)
            .map(aFruit => aFruit.number)
            .reduce((previous, current) => previous + current);
    })
});

ObjectProxy 是 Ember 1.x 中 itemController 的基础。请参阅 http://emberjs.com/api/classes/Ember.ObjectProxy.html 了解 ObjectProxy 的工作原理。 希望这会有所帮助。

【讨论】:

  • 这正是我所需要的。谢谢你。一个小问题 - 我相信在 person-proxy.js 中你需要 Ember.ObjectProxy.extend 而不是 Ember.ObjectProxy.create 否则(无论如何在 Ember 1.13 中)它会引发弃用警告。
【解决方案2】:

要在没有 itemController 的情况下执行此操作,您需要定义一个组件(在您的情况下可能称为 person-item)。实际上,组件只是一个控制器-模板对,在概念上从其他所有事物中抽象出来。在名为 person 的组件上定义一个属性,并在 {{each}} 循环中将模型分配给它。

此时,person-item.js 文件(组件逻辑)现在是您的项目控制器,现在它拥有自己的模板(person-item.hbs)。

所以代码是相同的(几乎),但模板现在在一个单独的文件中。

【讨论】:

  • 感谢您的回答,但我仍然看不到如何对计算属性(本示例中为 numberOfSelectedFruit)进行排序,因为它现在是在组件上设置的,该组件不适用于控制器中的排序函数,它正在查看模型数据数组(不是组件)?
  • @Gaurav 有权进行排序 - 使用代理 - 你是对的,它应该是 .extend,而不是 .create,因为你正在定义代理类(扩展 ObjectProxy)而不是创建实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2013-09-22
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多