How to call method of a component from a controller


#1

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>

#2

I don’t think components are supposed to allow that type of outside access, instead being isolated and only working with the attributes passed into them and having their own actions bubble outside.

My experience with them is quite limited but I would instead expose a location attribute which is passed to the component, that way your controller can read or set the location of the map.

{{google-map location=mapLocation}}
<button {{action "centerMap"}}>Center Map</button>
App.PlacesController = Ember.Controller.extend
  mapLocation: null

  actions:
    centerMap: ->
      centerCoords = [x, y]
      @set 'mapLocation', centerCoords

Alternatively, if all {{google-map}} instances should have centering functionality you could pass in a centerLocation attribute to the component and then handle the centring in your components actions hash.


#3

The problem sharing the map location property is that I will need to duplicate the code that calculate the center of the map in serveral controllers.

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

Maybe it is a bad pattern but I don’t see the reason. Any thoughts?


#4

Why not make the button element part of your component?


#5

This is a simple code to illustrate the problem. The interaction could be more complex, for example, the controller has a a form that create a new marker and then the map should show all markers.


#6

I guess my point is that if the state of your component needs to be manipulated from the outside, maybe the scope of your component is too narrow? (I don’t know the right answer here, but that’s been my general rule of thumb)


#7

You could have something like a location attribute and a displayLocation attribute?

displayLocation would be the coordinates currently being displayed, and by default would be the same as location. It would update as users pan around the map etc…

The center map button could then set the component’s displayLocation to location which would re-focus the map on the original location.


#8

I’m also bumping up against this issue. Is there really no canonical way to access a public API on a component?

Binding the internal state of a component to properties on my controller kind of defeats the purpose of trying to encapsulate complex behavior in a component in the first place.

Also, it seems that the viewName property no longer works in the latest Ember builds.