动态更改子视图

时间:2014-03-17 14:29:49

标签: javascript ember.js handlebars.js

使用EmberJs我必须创建一个可以包含播放器的视图(如Youtube,Photosynth,Html COntent,ecc。),它必须根据包含要播放的项目的控制器属性动态更改。

我创建了一些视图,这些视图是每种类型内容的播放器,如本例中的

App.basePlayer = Em.View.extend({
    templateName : 'base'
  });

App.playerEmpty= App.basePlayer.extend({
    templateName : 'empty'
  });

App.player1= App.basePlayer.extend({
    templateName : 'p1'
  });

App.player2= App.basePlayer.extend({
    templateName : 'p2'
  });

现在我必须创建一个可以在其内容中附加其中一个视图的视图。 如果视图是一个普通的Ember.View,它在其内容中绑定一个存储在属性中的视图,它可以在初始化时工作,但很明显,如果我设置一个新视图,它将不会重新渲染。

为了解决这个问题,我创建了一个包含播放器的ContainerView:

App.IndexView = Em.CollectionView.extend({

  childViews: ['header', App.playerEmpty],

  header: Em.View.extend({
    templateName : 'h'
  })

});

然后我还创建了2个方法,当控制器中的属性Item更新时,它们会删除旧的播放器视图并添加与控制器项类型一致的新视图。

  onItemChange : function(){

    var item = this.get('controller.item'),
        playerClass = null;


    if(item === null){
      playerClass = App.playerEmpty;
    }

    else if(item instanceof App.Item1){  
      playerClass = App.player1;
    }
    else if(item instanceof App.Item2){  
      playerClass = App.player2;
    }

    this.setPlayerView(playerClass);


  }.observes('controller.item'),


  setPlayerView: function(playerClass){

    var v =this.get('childViews').find(function(item, index, enumerable){
      return item instanceof App.basePlayer;
    });

    this.get('childViews').removeObject(v);

    this.get('childViews').pushObject(playerClass.create());

  }

这是一个很好的解决方案还是有更好的解决方案?

这里有一个示例:http://emberjs.jsbin.com/naxuboyi/4/edit

1 个答案:

答案 0 :(得分:1)

在Ember.js中编写代码的首选模式是让您的视图依赖于模型中的属性。由于余烬'binding abilities,这些更改会自动反映在您的观看中。

在您的情况下,我创建了一个单独的播放器视图,该视图根据项目设置其模板。现在,您只有一个玩家视图,并且您的集合视图中没有观察者代码:

App = Ember.Application.create();

App.player = Em.View.extend({
  templateName : function() {
  item = this.get('content');
    if(item === null){
      return 'empty';
    }
    else if(item instanceof App.Item1){  
      return 'p1';
    }
    else if(item instanceof App.Item2){  
      return 'p2';
    } else {
      return 'base';
    }
  }.property('content')
});

App.IndexView = Em.CollectionView.extend({

  childViews: ['header', App.player],

  header: Em.View.extend({
    templateName : 'h'
  })

});

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

App.IndexRoute = Ember.Route.extend();

App.Item1 = Em.Object.extend({
  type : 1
});

App.Item2 = Em.Object.extend({
  type : 2
});

App.IndexController = Ember.Controller.extend({
  item: null,

  actions : {
    setItem : function(idx){
      switch(idx){
        case 0:
            this.set('item', null);
          break;
        case 1:
            this.set('item', App.Item1.create());
          break;
        case 2:
            this.set('item', App.Item2.create());
          break;
      }
    }
  }
});

这是一个简单的解决方案。如果您的不同玩家视图需要更复杂的行为更改并且确实需要不同的视图类,那么请查看programmatic creation of child views,但请避开观察者。