我使用的是带有AngularJS背景的EmberJS,这可能会让我遇到问题。我在<ul>
中有一个元素列表,我想用键盘来浏览它们。基本上,当我按下时,我会减少selectedIndex,当我按下时,我会增加它。
在我看来,我想比较元素的索引和selectedIndex变量,如果它们相等,则为它分配active
类。现在,在AngularJS中,我可以使用ng-class="getClass($index)"
,我会完成。
然而,在EmberJS中,我不知道最好的方法是什么。我已经读过,也许我可以创建自己的帮助器,或者使用collectionView。在我看来,为一个简单的比较创建一个帮助器有点过分。
目前,这是我的emberJS代码:
在template.hbs中:
<div id="command-manager">
<div class="right-inner-addon">
{{input id="searchInput" type="search" class="form-control" onEvent="keyUp" action="search" placeholder="{{t command-manager.searchInput.placeholder }}" maxlength="32"}}
<a {{ action "clearSearch" }} class="close"><span aria-hidden="true">×</span></a>
</div>
<div class="suggestions">
<ul>
{{#each suggestion in cm.suggestions.elements}}
<li class="{{ cm.suggestions.getClass(index)}}">{{ suggestion.show }}</li>
{{/each}}
</ul>
</div>
</div>
在我的component.hbs中:
var CommandManagerComponent = Ember.Component.extend({
cm: new CommandManager(),
keyUp: function(e) {
if(e.keyCode === 38) { // up arrow
this.get('cm').changeSuggestion('up');
console.log('up arrow');
}
else if(e.keyCode === 40) { //down arrow
this.get('cm').changeSuggestion('down');
console.log('down arrow');
}
else {
this.get('cm').receiveCommand(e.target.value);
}
},
didInsertElement: function() {
},
actions:{
search:function(text) {
this.get('cm').receiveCommand(text);
},
clearSearch: function() {
$('#searchInput').val('');
this.get('cm').clearSuggestions();
}
}
});
export default CommandManagerComponent;
在我的commandManager文件中 ¸
var suggestions = Ember.Object.extend({
getClass: function(index) {
if(index == this.get('selected')) {
return 'active';
}
}.property('selected')
})
self.suggestions = suggestions.create({
'elements': Ember.A(),
'selected' : -1
});
self.changeSuggestion = function(direction) {
var selectedSuggestion = self.suggestions.get('selected');
if(direction == 'up') {
if(selectedSuggestion <= 0) {
selectedSuggestion = self.suggestions.elements.toArray().length - 1;
}
else {
selectedSuggestion--;
}
}
else if(direction == 'down') {
if(selectedSuggestion >= (self.suggestions.elements.toArray().length - 1)) {
selectedSuggestion = 0;
}
else {
selectedSuggestion++;
}
}
self.suggestions.set('selected', selectedSuggestion);
console.log(self.suggestions);
};
所以,我打算使用{{ cm.suggestions.getClass(index)}}
来返回课程,但我觉得这不是最好的方法。
如果有人可以指导我,我会非常感激!
答案 0 :(得分:1)
这是您所描述的一个简单示例,它可能对您有所帮助
http://emberjs.jsbin.com/xareberi/1/edit
<强> JS 强>
App.Option = Ember.Object.extend({
id:null,
name:null,
isSelected:false
});
App.TestView = Ember.View.extend({
selectedOptionIndex:0,
keyUp: function(e) {
if(e.keyCode === 38) { // up arrow
if(this.get("selectedOptionIndex")>0){
this.decrementProperty("selectedOptionIndex");
}
}
else if(e.keyCode === 40) { //down arrow
console.log('down arrow');
if(this.get("selectedOptionIndex")<this.get("options").length-1){
this.incrementProperty("selectedOptionIndex");
}
}
},
updateSelectedOption:function(){
this.get("options").setEach("isSelected",false);
this.get("options")[this.get("selectedOptionIndex")].set("isSelected",true);
}.observes("selectedOptionIndex"),
options:[
App.Option.create({id:1,name:"option 1",isSelected:true}),
App.Option.create({id:2,name:"option 2"}),
App.Option.create({id:3,name:"option 3"}),
App.Option.create({id:4,name:"option 4"})
]
});
<强> HBS 强>
<script type="text/x-handlebars" data-template-name="test">
<i>please click on options and press key up/down</i>
<div tabindex="0" style="outline:none">
<ul>
{{#each option in view.options}}
<li {{bind-attr class="option.isSelected:active"}}>{{option.name}}</li>
{{/each}}
</ul>
</div>
</script>
答案 1 :(得分:1)
我会结合使用Em.ArrayProxy
和Em.ObjectProxy
。
目标很明确。你需要列表中每个项目的isSelected
属性。因此,请使用数据绑定的可能性来创建此属性。
所以,假设我们有以下数据:
[{
id: 1,
name: 'one'
},{
id: 2,
name: 'two'
},{
id: 3,
name: 'three'
}]
现在,你可以 在它们上面添加isSelected
属性,但这可能不是你想要的!
但是ObjectProxy可以给你一个额外的层来定义这个属性。
var maySelectedItem = Em.ObjectProxy.extend({
content: null,
currentIndex: null,
allItems: null,
isSelected: function() {
// just find out if its selected:
return this.get('allItems') && this.get('allItems').indexOf(this.get('content')) == this.get('currentIndex') || "NO";
}.property('content', 'allItems.@each', 'currentIndex')
});
现在你有一个很好的ObjectProxy。我已将content
,currentIndex
和allItems
取消,以确保它们不会被代理到content
属性,然后是其他所有内容,并明确表示应该设置它们然后创建该类的实例。
Soo,现在你需要用你想要的数据转换你的对象数组maySelectedItems数组。你可以使用[].map
,但使用与Em.ArrayProxy的实时数据绑定要冷得多:
var maySelectedItemList = Em.ArrayProxy.extend({
content: null,
currentIndex: null,
objectAtContent: function(idx) {
return maySelectedItem.create({
content: this.get('content').objectAt(idx),
outerArrayProxy: this,
allItemsBinding: 'outerArrayProxy.content',
currentIndexBinding: 'outerArrayProxy.currentIndex'
});
}
});
所以,现在你拥有你需要的一切!只需使用它:
App.IndexController = Em.Controller.extend({
content: null, // the array of items
selectedIndex: 0,
innerContent: function() {
return maySelectedItemList.create({
outerController: this,
contentBinding: 'outerController.content',
currentIndexBinding: 'outerController.selectedIndex'
});
}.property('content')
});