如何在Ember.js中的控制器之间进行通信

mr_*_*eko 8 ember.js

我想创建一个页面,在左边我有固定视图(一些过滤器),它们应用于右侧的结果.

例如,左侧是根据流派,标题,创建年份过滤电影的过滤器....右侧是不同的图表和表格,根据所选的过滤器进行更新.

所以我想在左边有一个固定的视图,然后在右边有一个根据路线改变的出口.

这是正确的方法吗?如果是,我无法弄清楚如何将过滤器更改传达给右侧的控制器.

这个JSFiddle显示了类似的设置:http://jsfiddle.net/DEHcK/2/

在ContentRoute - > setupController中,我得到一个NavigationController实例,但后来我无法弄清楚如何更改someValue.

在上面的示例中,ContentController如何在NavigationController中获取someValue的更改?

这是实现我在ember中描述的应用程序的正确方法吗?

JavaScript的:


    window.App = Ember.Application.create();

    App.Router.map(function () {
        this.route('content');
    });

    App.ContentRoute = Ember.Route.extend({
        setupController: function (controller) {
            controller.set('navigationController', this.controllerFor('navigation'));
        }
    });

    App.ContentController = Ember.ObjectController.extend({
        navigationController: null,
        observerOfSomeValue: function () {
            this.set('observedValue', this.get('navigationController.someValue'));
        }.observes('navigationController', 'navigationController.someValue'),
        observedValue: null
    });

    App.IndexRoute = Ember.Route.extend({
        redirect: function () {
            this.transitionTo('content');
        }
    });

    App.NavigationView = Ember.View.extend({
        init: function () {
            this._super();
            this.set('controller', this.get('parentView.controller').controllerFor('Navigation'));
        },
        templateName: "navigation"
    });

    App.NavigationController = Ember.ObjectController.extend({
        someValue: 'xx',
        observedValue: null,
        observerOfSomeValue: function () {
            this.set('observedValue', this.someValue);
        }.observes('someValue')
    });
Run Code Online (Sandbox Code Playgroud)

HTML:

<script type="text/x-handlebars" data-template-name="application" >
    <div>
        {{view App.NavigationView}}
    </div>
    <div>
        {{ outlet }}
    </div>
</script>

<script type="text/x-handlebars" data-template-name="navigation" >
    Change {{view Ember.TextField valueBinding="controller.someValue"}}
    <div>observed value in same view: {{controller.observedValue}}</div>
</script>

<script type="text/x-handlebars" data-template-name="content" >
    <div style="margin-top: 2em">
        observed value in another view: {{observedValue}}
    </div>
</script>
Run Code Online (Sandbox Code Playgroud)

Wil*_*ney 25

我已经为你创建了一个JSFiddle,它基本实现了你所追求的目标.我认为它值得贯穿始终,所以你可以抓住Ember.

路由器

我们现在正在配置IndexRoute我们存储所有歌曲的地方{{outlet}}.

App.IndexRoute = Ember.Route.extend({
    setupController: function(controller) {
        controller.set('content', [
            Ember.Object.create({ title: 'Stairway to Heaven', genre: 'Metal' }),
            Ember.Object.create({ title: 'Ratts of the Capital', genre: 'Post Rock' }),
            Ember.Object.create({ title: 'Wonderwall', genre: 'Brit Pop' }),
            Ember.Object.create({ title: 'Last Flowers', genre: 'Indie Rock' })
        ]);
    }
});
Run Code Online (Sandbox Code Playgroud)

很有可能这个代码将被替换为您的后端Ruby/PHP的某种AJAX调用.但就目前而言,我们将IndexRoute负责设置控制器(因此setupController).这个责任也可以在控制器本身上,并且抽象出AJAX调用可能是一个好主意,因为你将有许多类似的AJAX调用.

您也可以决定使用Ember的DataStore,它将再次改变控制器的实现.

索引控制器

接下来我们将设置我们的IndexController(我们SongsController真的是),我们希望这个控制器有两个职责:

  1. 存储歌曲(也许还可以从后端获取歌曲);
  2. 根据传递给它的过滤器过滤歌曲.

为此,我们创建了一个计算属性来过滤掉内容,因为我们不想content直接操作特殊数组.

App.IndexController = Ember.ArrayController.extend({
    content: [],
    excludeGenres: [],

    filteredContent: function() {
        var excludeTheseGenres = this.get('excludeGenres').mapProperty('genre');
        return this.get('content').filter(function(model) {
            return Boolean(jQuery.inArray(model.get('genre'), excludeTheseGenres) === -1);
        });
    }.property('excludeGenres.length', 'content.length')
});
Run Code Online (Sandbox Code Playgroud)

excludeGenres会采取类别对象的数组.例如,如果其中包含"Post Rock" excludeGenres,那么我们将不会显示任何"Post Rock"相关歌曲,但如果它不存在,那么我们将向他们展示!在IndexController没有责任维护这个数组,但它确实有它的过滤时,该阵列的内容负责更新.

流派控制器

也许是我们这个小应用程序中最令人困惑的控制器,因为它实际上并没有自己的任何内容,而是取决于它IndexController的内容.

App.GenresController = Ember.ObjectController.extend({
    needs: ['index'],

    genres: function() {
        return this.get('controllers.index').mapProperty('genre').uniq();        
    }.property('controllers.index.length'),

    toggle: function(genreName) {
        var indexController     = this.get('controllers.index'),
            genres              = indexController.get('excludeGenres'),
            genre               = indexController.findProperty('genre', genreName);

        if (genres.findProperty('genre', genreName)) {
            genres.removeObject(genre);
            return;
        }

        genres.pushObject(genre);
    }
});
Run Code Online (Sandbox Code Playgroud)

流派控制器的职责可以定义如下:

  1. 监视content数组IndexController并在其长度变化时获取唯一的类型名称;
  2. excludeGenres在用户单击列表中的类型以包含/排除数组时填充数组.

toggle调用该方法,我们需要在我们的流派视图中指定一个动作,以便在单击时调用它:<a {{action "toggle" genre}}>{{genre}}</a>.现在,只要用户点击某个流派,toggle就会调用该方法,并将流派名称作为第一个参数传递.

一旦我们进入该toggle方法,它将确定该类型是否已被排除.如果它被排除,那么它将被删除,反之亦然.一旦我们添加/删除了类型,filteredContent计算属性将再次触发,索引视图将无缝更新.

究其原因,GenresController实际上并没有自己的内容是,它似乎愚蠢的管理两个content阵列当两个有关系.由于类型可以从应用程序中存在的歌曲中确定,控制器可以从该列表中收集信息,并且只需提取它所需的信息 - 在我们的例子中,类型.

这样,如果添加/删除歌曲,则可以使类型列表保持同步.

结论

但是,我认为原始问题的答案是,为了使控制器彼此通信,您需要指定它所需要的内容(使用needs).