2013-10-27 20 views
22

Mam komponent reprezentujący mapę i po akcji w moim kontrolerze chcę wywołać metodę na komponencie, aby wyśrodkować mapę. Kod wygląda następującoJak wywołać metodę składnika ze kontrolera?

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


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

szablonu

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

Znalazłem obejście, ale nie sądzę, jest to sposób Ember to zrobić.

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

Odpowiedz

9

Można użyć on mieć swój składnik nasłuchiwać zdarzenia ze sterownika, a następnie można użyć trigger w kontrolerze emitować zdarzenia.

Więc w składniku może masz coś takiego:

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

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

A w kontrolerze Mogłeś:

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

Używam Ember 1.1.2, a EmberController nie ma metody wyzwalania. To jest właściwy wzór? Kontroler powinien uruchamiać zdarzenia, a widok ich wysłucha? – axelhzf

+0

@axelhzf Aby wywołać zdarzenia i odsłuchać je, musisz utworzyć obiekt, dodając mixin 'Ember.Evented', tak jak to:' App.someController = Ember.Controller.extend (Ember.Evented, {...}) ; ', możesz subskrybować zdarzenia i podnosić zdarzenia przy użyciu metod z mixu' Ember.Evented'. –

+0

Podoba mi się to rozwiązanie, ale nie widziałem wcześniej użycia .proxy - czy możesz dokładnie wyjaśnić, co to robi? –

23

W Ember, widoki (komponenty są uwielbiony wyświetleń) wie o ich kontroler, ale kontrolery NIE znają widoków. Jest to zgodne z projektem (MVC), aby rzeczy zostały rozdzielone, dzięki czemu możesz mieć wiele widoków, które są "zasilane" przez pojedynczy kontroler, a kontroler nie jest mądrzejszy. Więc kiedy myślisz o związku, zmiany mogą się zdarzyć z kontrolerem, a widok zareaguje na te zmiany. Tak więc, aby powtórzyć, nigdy nie powinieneś próbować uzyskać dostępu do widoku/komponentu z poziomu kontrolera.

Jest kilka opcji, które mogę wymyślić, gdy mamy do czynienia z twoim przykładem.

  1. Zrób część przycisku komponentu! Komponenty są przeznaczone do obsługi danych wprowadzanych przez użytkownika, takich jak kliknięcia przycisku, dlatego warto rozważyć nadanie temu przyciskowi części komponentu mapy i obsłużyć kliknięcia w mieszaniu działań komponentu. Jeśli przyciski te zawsze będą towarzyszyć komponentowi mapy, zdecydowanie zalecam takie podejście.

  2. Możesz mieć właściwość boolowską na kontrolerze, taką jak isCentered, a po kliknięciu przycisku jest ustawiona na wartość true. W składniku można powiązać właściwość tego kontrolera i reagować za każdym razem, gdy ta właściwość ulegnie zmianie. Jest to dwukierunkowe wiązanie, więc możesz również zmienić lokalnie powiązaną właściwość na wartość false, jeśli użytkownik przesunie mapę.

    Kontroler:

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

    Składnik:

    ... 
    isCenteredBinding: 'controller.isCentered', 
    onIsCenteredChange: function() { 
        //do your thing 
    }.observes('isCentered'), 
    ... 
    
  3. rozwiązanie Jeremy Greena może działać, jeśli mieszać w Ember.Evented wstawek do sterownika (który dodaje pub/sub trigger i on metody)

+0

Dziękuję za odpowiedź, może jestem mylić z wzorem Ember MVC. Jestem nowy w Ember. Myślałem, że kontroler komunikuje się z widokami za pośrednictwem metod wywoływania i widoków powinien komunikować się ze sterownikami za pośrednictwem zdarzeń, ale wydaje się wręcz przeciwnie. W ten ślizga https://docs.google.com/presentation/d/1y5AZN0qbjkMuyxxicfV_XPe_aLePdnkuR69tUOQTVo0/edit#slide=id.g121e8eb25_238 (zjeżdżalnia 7) jest jakaś bezpośrednia komunikacja między widokami i kontrolery ale mechanizm nie jest określona. Kto jest odpowiedzialny za tworzenie widoków i wywołanie metody renderowania lub niszczenia? Czy to nie kontroler? – axelhzf

+0

ember1.6, kontroler komponentu, a nie kontroler mvc. –

+0

1) tutaj ma sens, jeśli przycisk ma żyć gdzie indziej w domenie, zawsze warto zastanowić się nad add-emem w kształcie żarzącego się kanału. – Knightsy

3

Myślę, że to OK, aby mieć odniesienie w kontrolerze do komponentu. To prawda, że ​​twój komponent zawiera własne zachowanie, ale metody publiczne, takie jak reload itp., Są zupełnie w porządku.

Moim rozwiązaniem jest przekazanie bieżącego controller do komponentu i ustawienie właściwości kontrolera w komponencie.

Przykład

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

Teraz w kontrolerze można po prostu uzyskać odwołanie do komponentu z this.get("refComponent") .

Steffen

+0

Podczas gdy uważam, że jest to sprzeczne z filozofią Ember, znalazłem się w potrzebie zrobienia tego.Prawdopodobnie będę musiał przepisać mój kod później, ale działa to znakomicie. Dzięki Steffen. – neojp

+1

w tym kontroler wyzwala błąd asercji dla wersji ember> 2 – kumkanillam

5

Bind właściwość komponent do właściwości kontrolera w szablonie:

{{google-map componentProperty=controllerProperty}} 

Następnie obserwować właściwość komponentu w składniku:

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

Teraz za każdym razem controllerProperty zmienia się w sterowniku, onChange w komponencie zostanie wywołana.

Od this answer, akapit drugi.

Powiązane problemy