EmberJS - 根据索引设置活动

时间:2014-07-01 14:07:38

标签: javascript ember.js

我使用的是带有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">&times;</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)}}来返回课程,但我觉得这不是最好的方法。

如果有人可以指导我,我会非常感激!

2 个答案:

答案 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.ArrayProxyEm.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。我已将contentcurrentIndexallItems取消,以确保它们不会被代理到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')
});

在这里查看结果: http://emberjs.jsbin.com/yewuboga/4/edit