我有一个数组控制器中的项目列表。单击某个项目会使其“活动”#34;但我希望一次只能激活一个项目(类似于单选按钮)。
我通过将活动项存储在计算属性中,然后在阵列控制器上的操作中切换其活动状态来完成此操作,请参阅:http://emberjs.jsbin.com/wavay/2/edit
但是,这并不能处理通过某种其他方式激活某个项目的情况,即不通过该操作。
我已尝试观察isActive
更改(使用.observesBefore('@each.isActive')
),并翻转activeItem
的状态,但当然,此方法会导致无限循环。
有更好的方法吗?
答案 0 :(得分:1)
这可以使用Ember.reduceComputed
和观察者的组合来解决。
removedItem
中的addedItem
和Ember.reduceComputed
回调可以访问已更改的对象,以及instanceMeta
,可用于存储“有效” “item:
App.IndexController = Ember.ArrayController.extend({
itemController: 'item',
activeItem: Ember.reduceComputed('@this.@each.isActive', {
initialValue: null,
removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
if (item.get('isActive')) {
var previousActiveItem = instanceMeta.activeItem;
if (previousActiveItem) previousActiveItem.set('isActive', false);
return instanceMeta.activeItem = item;
}
return instanceMeta.activeItem = null;
},
addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
return instanceMeta.activeItem;
}
})
…
但是,如果未在任何地方访问activeItem
,则永远不会调用removedItem
和addedItem
,因此在手动切换之前,项目将保持有效状态。要解决此问题,可以将观察者设置为在this.get('activeItem')
属性发生更改时调用isActive
:
setActiveItem: function () {
this.get('activeItem');
}.observes('@each.isActive')
请参阅更新的jsbin:http://emberjs.jsbin.com/wavay/3/edit?js,output
相关:David Hamilton关于Array Computing Properties的演讲。
答案 1 :(得分:0)
基于您的toggleActive实施的可能解决方案可用here。
如果仅使用toggleActive控制器方法更新“active”标志,则此解决方案有效。到目前为止控制器代表状态,有意义的是提供api来正确更新其数据。
App.IndexController = Ember.ArrayController.extend({
itemController: 'item',
activeItem: function() {
return this.findBy('isActive');
}.property('@each.isActive'),
toggleActiveModel: function(model) {
var controller = this.findBy('model', model);
this._toggleActive(controller);
},
_toggleActive: function(controller) {
var previouslyActive = this.get('activeItem');
if(previouslyActive && previouslyActive !== controller) {
previouslyActive.set('isActive', false);
}
controller.set('isActive', !controller.get('isActive'));
},
actions: {
toggleActive: function(controller) {
this._toggleActive(controller);
},
toggle: function(modelValue) {
this.toggleActiveModel(modelValue);
}
}
});