ember.js |在一个组件操作上通知其他组件

时间:2013-08-03 17:42:15

标签: ember.js

components section at Ember's guides中有发布摘要组件的演示, 点击一个Post Summery标题会打开它下面的内容。

我想添加功能以同时关闭任何其他已打开的帖子摘要。

我的问题的目的是理解ember如何在不牺牲隔离的情况下在组件之间说话。

我想到的解决方案是:

  1. 有一些以某种方式处理它的包装器组件

  2. 触发像'post-summery:open'这样的事件并让其他组件靠近它(但是它可以使用相同的组件与app上的其他地方碰撞以进行不同的使用)

    < / LI>

    这是文档中的原始演示: http://jsbin.com/uyibis/1/edit

    这就是我用jQuery实现行为的方法: http://jsbin.com/eremon/2/edit

      

    var $ contents = $('。content')。hide();

         

    $(document).on('click','。title',function(){

         

    $ contents.hide();
        $(本)的.next( '内容')显示();

         

    });

    enter image description here

2 个答案:

答案 0 :(得分:5)

这个问题一直在Ember出现。我解决它的方法是跟踪控制器上哪个帖子“打开”,然后让每个项目的视图根据该数据负责自己的状态。这样,每次切换时,您都不必手动重置每个帖子的状态。

规范的真相来源是控制者。

App.IndexController = Ember.ArrayController.extend({
    content: null,
    selectedPost: null // null means no post selected
});

我们通过模板将这些信息连接到组件。

<script type="text/x-handlebars" data-template-name="index">
    {{#each post in controller}}
        {{post-summary post=post selectedPost=selectedPost}}
    {{/each}}
</script>

<script type="text/x-handlebars" id="components/post-summary">
    <h3 {{action "toggleBody"}}>{{post.title}}</h3>
    {{#if isShowingBody}}
        <p>{{{post.body}}}</p>
    {{/if}}
</script>

现在,可以通过属性计算给定帖子的正文可见性。

App.PostSummaryComponent = Ember.Component.extend({
    post: null,
    selectedPost: null,

    isShowingBody: function() {
        return this.get('selectedPost') === this.get('post');
    }.property('selectedPost', 'post'),

    toggleBody: function() {
        this.set('selectedPost', 
                 this.get('isShowingBody') ? null : this.get('post'));
    }    
});

Here's the jsfiddle

有人可能会说这不是一个理想的面向对象的解决方案,但它已经彻底改善了我的Ember应用程序的结构和可维护性。您可以通过让每个元素基于共同的事实来源来管理自己的状态来实现各种复杂的列表行为。

答案 1 :(得分:2)

使用Ember.Component您无法控制childViews,因此我使用Ember.CollectionView来管理项目。由于App.PostSummaryComponent已经扩展Ember.Component,因此我使用模板中的Ember.CollectionView委托view containerViewClass该行为。所以我们拥有两个世界中最好的一个。

由于containerViewClass属性是一个类,我们需要一种方法来访问该实例 - 在创建视图时与childViews进行交互。为此,您必须在模板中使用viewName='containerView'。这告诉Ember,containerViewClass的新实例将在名为containerView的属性中设置。因此,我们可以在this.get("containerView")中使用App.PostSummaryComponent

最后一项更改是将each帮助程序从索引模板移动到组件模板。所以其他人对该组件的调用不需要重复它。

http://jsbin.com/ebayip/2/edit