I have a component that represent a map and after an action in my controller I want to call a method on the component to center the map. The code looks like this
App.PlacesController = Ember.Controller.extend({ actions : { centerMap : function () { // how to call from here to GoogleMapComponent.centerMap ?? } } }); App.GoogleMapComponent = Ember.Component.extend({ centerMap : function () { } });
template
{{google-map}} <button {{action "centerMap"}}>Center Map</button>
I have found a workaround but I don't think this is the Ember way of doing this.
{{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(); } });
Controllers are apex classes so you just need to instantiate your second controller in the first, set whatever data you need to set and then call the method like any other class.
In Ember, views (Components are glorified views) know about their controller, but controllers do NOT know about views. This is by design (MVC) to keep things decoupled, and so you can have many views that are being "powered" by a single controller, and the controller is none the wiser. So when thinking about the relationship, changes can happen to a controller and a view will react to those changes. So, just to reiterate, you should never try to access a view/component from within a controller.
There are a few options I can think of when dealing with your example.
Make the button part of your component! Components are meant to handle user input, like button clicks, so you may want to consider making the button a part of the map component and handle clicks in the actions hash of your component. If this buttons is always going to accompany the map component, then I certainly recommend this approach.
You could have a boolean property on your controller like isCentered
, and when the button is clicked it's set to true. In your component you can bind to that controller's property, and react whenever that property changes. It's a two-way binding so you can also change your locally bound property to false if the user moves the map, for example.
Controller:
... isCentered: false, actions: { centerMap: { this.set('isCentered', true); } } ...
Component:
... isCenteredBinding: 'controller.isCentered', onIsCenteredChange: function () { //do your thing }.observes('isCentered'), ...
Jeremy Green's solution can work if you mix in the Ember.Evented mixin into the controller (which adds the pub/sub trigger
and on
methods)
You can use on
to have your component listen for an event from the controller, then you can use trigger
in the controller to emit an event.
So in your component you might have something like this:
didInsertElement : function(){ this.get('controller').on('recenter', $.proxy(this.recenter, this)); }, recenter : function(){ this.get("mapView").centerMap() }
And in your controller you could have :
actions : { centerMap : function () { this.trigger('recenter'); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With