2013-02-13 87 views
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') 
    }); 

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> 
+0

感謝@Wildhoney,這是一個更新的小提琴。 http://jsfiddle.net/DEHcK/3/ – 2013-02-14 10:36:07

回答

25

我已經基本實現你以後已先行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' }) 
     ]); 
    } 
}); 

這段代碼很可能會被某種類型的AJAX調用替換爲您的後端Ruby/PHP。暫時,我們會給IndexRoute負責設置控制器(因此setupController)。這個責任也可能與控制器本身有關,並且抽象出AJAX調用可能是一個好主意,因爲您會有許多類似的AJAX調用。

您也可以決定use Ember's DataStore,這將再次更改控制器的實施。

指數控制器

接下來,我們要建立我們的IndexController(這是我們SongsController真的),我們希望這個控制器有兩個職責:

  1. 要存儲的歌曲(和也許是爲了從後端獲取歌曲);
  2. 根據傳入的過濾器來過濾歌曲。

爲此,我們創建一個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將採用一組流派對象。例如,如果「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 computed屬性將再次被觸發,並且索引視圖將被無縫更新。

GenresController實際上並沒有自己的內容的原因是當兩者有關係時管理兩個content數組似乎很愚蠢。由於可以根據應用程序中存在的歌曲來確定流派,因此控制器可以從該列表中收集信息,並只需提取它所需的信息 - 在我們的案例中,流派。

這樣,如果歌曲被添加/刪除,那麼流派列表可以保持同步。

結論

我覺得然而回答你原來的問題是,是爲了讓控制器能夠彼此進行通信,你需要指定它需要(與needs)。

+0

Wow @Wildhoney,幫助很大。非常感謝你。你的回覆中有很多有用的東西。我也經歷了大部分其他答案並學到了很多東西。 – 2013-02-14 10:47:25

+0

我很高興它幫助!有任何問題,請詢問。 – Wildhoney 2013-02-14 13:32:01

1

needs對於Ember控制器已被棄用,並在Ember 2.0中被刪除 - 看看它的Deprecation Guide

複製/粘貼在這裏指導,而不是寫:

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控制器。欲瞭解更多信息,請參閱the API documentation

相關問題