8

左側に固定ビュー(いくつかのフィルター)があり、右側の結果に適用されるページを作成したいと思います。

たとえば、左側には、ジャンル、タイトル、作成年で映画をフィルタリングするためのフィルターがあります。右側には、選択したフィルターに基づいて更新されるさまざまなチャートと表があります。

そこで、左側に固定ビュー、右側にルートに応じて変化する出口を考えていました。

これは正しい方法ですか?もしそうなら、フィルターの変更を右側のコントローラーに伝える方法がわかりません。

このJSFiddleは、同様の設定を示しています:http: //jsfiddle.net/DEHcK/2/

ContentRoute-> setupControllerで、NavigationControllerのインスタンスを取得しますが、someValueへの変更を取得する方法がわかりません。

上記の例では、ContentControllerはNavigationControllerのsomeValueへの変更をどのように取得できますか?

これは、残り火で説明したアプリを実装する正しい方法ですか?

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>
4

2 に答える 2

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

このコードは、バックエンドのRuby/PHPに対するある種のAJAX呼び出しに置き換えられる可能性があります。ただし、当面はIndexRoute、コントローラーのセットアップの責任を負います(したがってsetupController)。この責任はコントローラー自体にもある可能性があり、同様のAJAX呼び出しが多数あるため、AJAX呼び出しを抽象化することをお勧めします。

また、 Emberのデータストアを使用することもできます。これにより、コントローラーの実装が再び変更されます。

インデックスコントローラー

次に、IndexControllerSongsController実際には)セットアップを行います。このコントローラーに2つの責任を持たせます。

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

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

ジャンルコントローラーの責任は次のように定義できます。

  1. contentの配列を監視しIndexController、長さが変更されたときに一意のジャンル名をフェッチします。
  2. excludeGenresユーザーがリスト内のジャンルをクリックしてそれを含める/除外するときに配列にデータを入力します。

メソッドをtoggle呼び出すには、ジャンルビューでアクションを指定して、クリックしたときに呼び出す必要があります<a {{action "toggle" genre}}>{{genre}}</a>。これで、ユーザーがジャンルをクリックするたびにtoggleメソッドが呼び出され、ジャンル名が最初の引数として渡されます。

toggleメソッドに入ると、そのジャンルがすでに除外されているかどうかが判断されます。除外されている場合は削除され、その逆も同様です。ジャンルを追加/削除すると、filteredContent計算されたプロパティが再度起動され、インデックスビューがシームレスに更新されます。

GenresControllerが実際に独自のコンテンツを持たない理由は、2つcontentのアレイに関係がある場合、2つのアレイを管理するのはばかげているように見えるためです。ジャンルはアプリケーションに存在する曲から決定できるため、コントローラーはそのリストから情報を収集し、必要な情報(この場合はジャンル)を引き出すことができます。

このように、曲が追加/削除された場合、ジャンルリストの同期を維持できます。

結論

ただし、元の質問に対する答えは、コントローラーが相互に通信するためには、必要なものを(で)指定する必要needsがあるということだと思います。

于 2013-02-14T01:09:01.083 に答える
1

needsfor Ember Controllersは非推奨になり、Ember2.0で削除されました。非推奨ガイドをご覧ください。

書く代わりに、ここにガイドをコピーして貼り付けるには:

Ember.Controller.extend({
  needs: ['comments'],
  newComments: Ember.computed.alias('controllers.comments.newest')
});

あなたは書くべきです:

Ember.Controller.extend({
  comments: Ember.inject.controller(),
  newComments: Ember.computed.alias('comments.newest')
});

Ember.inject.controller()割り当てられたキーと同じ名前のコントローラー(この場合はcommentsコントローラー)を遅延検索します。詳細については、APIドキュメントを参照してください。

于 2015-10-07T10:48:18.853 に答える