Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call method of a component from a controller

Tags:

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();   } }); 
like image 989
axelhzf Avatar asked Oct 27 '13 13:10

axelhzf


People also ask

Can we call one controller from another controller in Salesforce?

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.


2 Answers

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.

  1. 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.

  2. 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'), ... 
  3. 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)

like image 138
Jason Monma Avatar answered Oct 20 '22 13:10

Jason Monma


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');   } } 
like image 37
Jeremy Green Avatar answered Oct 20 '22 13:10

Jeremy Green