如何突出显示所选地址?

How to highlight selected address?

如果用户单击 li 条目,它会触发 useThisAddress 操作,将 address 对象中的 isSelected 设置为 true。从那里 bind-attr 负责设置适当的 class (即“border-black”)。

这是解决这个问题的正确方法吗?或者有更好的方法吗?

下面的代码有效。但是,我对在 address 对象上将 isSelected 设置为 true 有点不确定,因为它在 address 对象模型中不是真正的 属性 .

// Controller
import Ember from 'ember';

export default Ember.Controller.extend({
  active: null,

  actions: {
    useThisAddress: function(address) {
      address.set('isSelected', true);
      var active = this.get('active');
      if (active) {
        active.set('isSelected', false);
      }
      this.set('active', address);
    }
  }
})

// Template
<ul>
  {{#each address in model}}
    <li {{bind-attr class='address.isSelected:border-black'}} {{action 'useThisAddress' address}}>
      Address: {{address.address1}} {{address.address2}}, {{address.city}}, {{address.postalCode}}
    </li>
  {{/each}}
</ul>

按照建议here,您可以在控制器中存储一个包含所选项目的单独列表。

我自己正在学习 Ember,但是......我的 .02.

列表方法是必须的,Ember不像 IMO。

假设您希望 isSelected 是准持久性的,您这样做的方式应该没问题。只要对象停留,它就会一直停留——甚至可能在路线更改之间(取决于您的模型)。

如果它应该是更短暂的..将地址扔到一个组件中并将isChecked存储在组件控制器中。

当您说它在您的对象模型上不是真实的 属性 时,我假设您的意思只是它没有被持久化。如果是这种情况,并且除了当前显示之外,该标志在任何地方都没有其他用途,则长期解决方案将是使用一个组件。参见:http://jsbin.com/colacu/1

App = Ember.Application.create();

App.Router.map(function() {
  // put your routes here
});

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return [Ember.Object.create({
      address1: 'add1',
      address2: 'add2',
      city: 'Washington'
    }),
    Ember.Object.create({
      address1: 'add1 again',
      address2: 'add2 again',
      city: 'Seattle'
    })];
  }
});

App.IndexController = Ember.Controller.extend({
  active: null,
  actions: {
    useThisAddress: function(address) {
      address.set('isSelected', true);
      this.set('active', address);
    }
  }
});

App.XAddressComponent = Ember.Component.extend({
  isSelected: false,
  address: null,
  tagName: 'li',
  classNameBindings: ['isSelected'],
  click: function() {
    console.log('clicked!');
    this.sendAction('action', this);
  }
});

模板:

  <script type="text/x-handlebars" data-template-name="index">
    Selected: {{selected.value}}
    <ul>
    {{#each model as |item|}}
      {{x-foo value=item action="select"}}
    {{/each}}
    </ul>
  </script>
  <script type="text/x-handlebars" data-template-name="components/x-foo">
    {{value}}
  </script>

不过你有的应该没问题。

我认为你的直觉反应是正确的 - 你不应该在你的模型上设置与你的 UI.

严格相关的属性

组件是 Ember 中用于存储 UI 层状态的构建块。在 Ember 中这是一个有点棘手的时间,因为控制器也用于此目的,但它们正在淘汰。很快就会是所有组件。

遇到你这种情况(list-with-selected-items),我一般会做一个list组件和一个list-item组件。 list 知道哪个项目被选中,每个 list-item 知道它是否被选中。对于您的简单案例,其他解决方案之一可能更直接,但我发现通常使用这些列表,您最终会需要更多功能(绑定到所选项目、更复杂的模板等)。

所以一种方法可能如下所示:

{{#address-list selected=selectedAddress as |list|}}
  {{#each address in model}}
    {{#address-list-item item=address list=list}}
      <p>{{address.address1}}</p>
    {{/address-list-item}}
  {{/each}}
{{/address-list}}

您使用块参数(注意:Ember 需要 1.10 或更高版本)将 <address-list> 传递到每个 <address-list-item>。现在,您的地址列表项可以通过向其发送操作来告知列表已选择新地址:

App.AddressListItemComponent = Ember.Component.extend({
  classNameBindings: ['active'],

  active: function() {
    return this.get('list.selected') === this.get('item');
  }.property('list.selected', 'item'),

  click: function() {
    this.get('list').send('select', this.get('item'));
  }
});

App.AddressListComponent = Ember.Component.extend({
  actions: {
    select: function(item) {
      this.set('selected', item);
    }
  }
});

这会为您设置所有绑定,将 .active class 添加到每个 <address-list-item>,并让您绑定到 <address-list> 的所选项目在模板之外。

See a working JSBin here.

现在,像这样针对 list 使用 .send 很尴尬,这正是我们很快就能将操作向下传递到子组件的原因(查看 Road to Ember 2.0 指南并搜索 "Improving Actions")。一旦该功能落地,您将能够将 select 操作处理程序从 <address-list> 直接传递到每个 <address-list-item>。但就目前而言,这是一种可行的方法,当这些更改落地时,它将使重构变得非常简单。