ember.js - 如何在Ember.js中的 Controller 之间进行通信

标签 ember.js

我想创建一个页面,该页面的左侧有固定 View (一些过滤器),这些 View 应用于右侧的结果。

例如,左侧的过滤器可按流派,标题,创作年份...来过滤电影。
右侧是不同的图表和表格,它们会根据所选过滤器进行更新。

所以我当时想在左边有一个固定的 View ,然后在右边有一个可以根据路线改变的导出。

这是正确的方法吗?如果是这样,我不知道如何将过滤器更改传达给右侧的 Controller 。

此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')
    });

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>

最佳答案

我继续了created you a 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' })
        ]);
    }
});

这个代码很有可能会被后端Ruby/PHP的某种AJAX调用所取代。暂时,我们将给IndexRoute负责设置 Controller 的职责(因此setupController)。这个责任也应该由 Controller 本身承担,并且抽象出AJAX调用可能是一个好主意,因为您将有许多类似的AJAX调用。

您也可以决定使用use Ember's DataStore,它将再次更改 Controller 的实现。

索引 Controller

接下来,我们将设置我们的IndexController(这实际上是我们的SongsController),我们希望此 Controller 承担两项职责:
  • 存储歌曲(也许还可以从后端获取歌曲);
  • 根据传递到其中的过滤器过滤歌曲。

  • 为此,我们创建了一个computed property来过滤内容,因为我们实际上并不希望直接操作特殊的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')
    });
    
    excludeGenres将采用一个流派对象数组。例如,如果excludeGenres中包含“Post Rock”,那么我们将不会显示任何与“Post Rock”相关的歌曲,但是如果不存在,我们将显示它们! IndexController不负责维护此数组,但确实负责在更新此数组时过滤其内容。

    流派 Controller

    在我们的小应用程序中,也许是最令人困惑的 Controller ,因为它实际上没有自己的任何内容,而是取决于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);
        }
    });
    

    体裁负责人的职责可以这样定义:
  • 监视contentIndexController数组,并在长度改变时获取唯一的流派名称。
  • 当用户单击列表中的流派以包括/排除该流派时,填充excludeGenres数组。

  • 要调用toggle方法,我们需要在流派 View 中指定一个操作以在单击时调用它:<a {{action "toggle" genre}}>{{genre}}</a>。现在,每当用户单击一个流派时,就会调用toggle方法,并将流派名称作为第一个参数传递。

    一旦进入toggle方法,它将确定该类型是否已被排除。如果将其排除在外,则将其删除,反之亦然。一旦添加/删除了流派,就将再次触发oj​​it_code计算属性,并且索引 View 将无缝更新。
    filteredContent实际上没有自己的内容的原因是,当两个GenresController数组有关系时,管理两个content数组似乎很愚蠢。由于可以根据应用程序中存在的歌曲确定流派,因此 Controller 可以从该列表中收集信息,然后提取所需的信息(在我们的示例中为流派)。

    这样,如果添加/删除了歌曲,则流派列表可以保持同步。

    结论

    我认为您的原始问题的答案是,为了使 Controller 之间能够相互通信,您需要指定需要(使用needs)。

    关于ember.js - 如何在Ember.js中的 Controller 之间进行通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14862973/

    相关文章:

    javascript - 操作后 Ember 更新模型

    ember.js - Ember : difference between unloadRecord and destroy for new records

    javascript - Ember 的 titleBinding on a link-to helper 破坏了 Jasmine 测试

    ruby-on-rails - Ember 中的全局变量

    javascript - 在 Ember.js 中使用 itemController 时可以有自定义 View 吗?

    javascript - 如何克隆 ember 对象

    javascript - Emberjs - 循环遍历数组 'each' ,但每三个对象执行不同的操作

    javascript - 浏览器返回不渲染我的上一页

    ember.js - Handlebars 条件类属性

    ember.js - Ember RSVP Promise 解析总是返回未定义的值