2013-10-27 21 views
22

我有一個組件代表地圖,並且在我的控制器中的一個操作之後,我想調用組件上的方法來使地圖居中。該代碼看起來像這樣如何從控制器調用組件的方法

App.PlacesController = Ember.Controller.extend({ 
    actions : { 
    centerMap : function() { 
     // how to call from here to GoogleMapComponent.centerMap ?? 
    } 
    } 
}); 


App.GoogleMapComponent = Ember.Component.extend({ 
    centerMap : function() { 
    } 
}); 

模板

{{google-map}} 
<button {{action "centerMap"}}>Center Map</button> 

我已經找到了一個解決辦法,但我不認爲這是這樣做的灰燼方式。

{{google-map viewName="mapView"}} 
<button class="center-map">Center Map</button> 

App.PlacesView = Ember.View.extend({ 
    didInsertElement : function() { 
    this.$(".center-map").click(this.clickCenterMap.bind(this)); 
    }, 

    clickCenterMap : function() { 
    this.get("mapView").centerMap(); 
    } 
}); 

回答

9

您可以使用on有您的組件偵聽來自控制器的事件,那麼你可以使用trigger控制器發出的事件。

所以在你的組件,你可能有這樣的事情:

didInsertElement : function(){ 
    this.get('controller').on('recenter', $.proxy(this.recenter, this)); 
}, 

recenter : function(){ 
    this.get("mapView").centerMap() 
} 

而在你的控制器,你可以有:

actions : { 
    centerMap : function() { 
    this.trigger('recenter'); 
    } 
} 
+0

我使用Ember 1.1.2並且EmberController沒有觸發方法。 這是正確的模式?控制器應該啓動事件並且視圖聽取它們? – axelhzf

+0

@axelhzf要觸發事件並偵聽它們,您需要通過添加'Ember.Evented'混合來創建一個對象,如下所示:'App.someController = Ember.Controller.extend(Ember.Evented,{...}) ;',那麼你可以使用'Ember.Evented'混合中的方法來訂閱事件並引發事件。 –

+0

我喜歡這個解決方案,但是我之前沒有看到$ .proxy的使用 - 你能澄清一下到底做了什麼嗎? –

23

在灰燼,視圖(Components是榮耀的觀點)瞭解自己控制器,但控制器不知道視圖。這是通過設計(MVC)來保持事物分離的,因此您可以擁有許多由單個控制器「供電」的視圖,而且控制器並不聰明。因此,在考慮關係時,控制器可能會發生變化,視圖會對這些變化做出反應。因此,僅僅爲了重申一下,您絕不應該嘗試從控制器內訪問視圖/組件。

在處理您的示例時,我可以考慮幾個選項。

  1. 使按鈕成爲您的組件的一部分!組件是爲了處理用戶輸入,如按鈕點擊,所以你可能想考慮使按鈕成爲地圖組件的一部分,並處理組件的動作哈希中的單擊。如果這個按鈕總是伴隨地圖組件,那麼我肯定會推薦這種方法。

  2. 您可以在控制器上擁有像isCentered這樣的布爾屬性,並且當單擊該按鈕時,它將設置爲true。在您的組件中,您可以綁定到該控制器的屬性,並在屬性發生變化時作出反應。這是一個雙向綁定,例如,如果用戶移動地圖,您也可以將您的本地綁定屬性更改爲false。

    控制器:

    ... 
    isCentered: false, 
    actions: { 
        centerMap: { 
         this.set('isCentered', true); 
        } 
    } 
    ... 
    

    組件:

    ... 
    isCenteredBinding: 'controller.isCentered', 
    onIsCenteredChange: function() { 
        //do your thing 
    }.observes('isCentered'), 
    ... 
    
  3. 如果在Ember.Evented混入到控制器混合(其中添加的pub/sub傑里米綠色的解決方案可以工作triggeron方法)

+0

謝謝你的回答,也許我對Ember MVC模式感到困惑。我是Ember的新人。 我認爲Controller通過調用方法與視圖進行通信,視圖應該通過事件與控制器通信,但它似乎恰恰相反。 在此幻燈片中https://docs.google.com/presentation/d/1y5AZN0qbjkMuyxxicfV_XPe_aLePdnkuR69tUOQTVo0/edit#slide=id.g121e8eb25_238(幻燈片7)視圖和控制器之間存在一些直接通信,但未指定機制。 誰負責創建視圖並調用渲染或銷燬方法?不是控制器嗎? – axelhzf

+0

ember1.6,組件的控制器不是mvc的控制器。 –

+0

1)這裏最有意義的是,如果按鈕必須住在其他地方,它總是值得考慮燼蟲插件 – Knightsy

3

我認爲這是可以在控制器中爲您的組件提供參考。確實,你的組件封裝了它自己的行爲,但像reload等公共方法是非常好的。

我的解決方案是將當前的controller傳遞給組件,並在組件內的控制器上設置一個屬性。

template.hbs:

{{#component delegate=controller property="refComponent"}}

component.js:

init: function() { 
    this._super.apply(this, arguments); 

    if (this.get("delegate")) { 
     this.get('delegate').set(this.get("property") || "default", this); 
    } 
} 

現在在你的控制器,你可以簡單地得到一個引用您的組件與this.get("refComponent")

斯特芬

+0

雖然我發現這是違反Ember philoshopy,但我發現自己需要這樣做。之後我可能不得不重寫我的代碼,但它可以作爲一個很好的解決方法。謝謝Steffen。包含控制器的 – neojp

+1

將觸發ember版本> 2的斷言錯誤 – kumkanillam

5

綁定一個組件的屬性控制器屬性模板:

{{google-map componentProperty=controllerProperty}} 

再觀察組件中的組件屬性:

onChange: function() { 
     // Do your thing 
    }.observes('componentProperty') 

現在每次controllerProperty控制器改變,在組件onChange將被調用。

this answer,第二段。

相關問題