Communication between components

Now that Ember is moving towards Component usage over View/Controllers, and one-way binding, how would ancestor components interact/communicate with each other? Also, will there be support for Component Containers…a Parent Component having direct access to its Child Components?

I think the general idea is that your route creates a data structure which your components then render. To “communicate” with other components you would send an event from your component up to the actions in your route which in turn modify your data structure which causes your components to update accordingly. This is the flow the data-down, actions-up refers to (which is the recommended approach now and the direction for ember 2).

2 Likes

What if you are trying to communicate (between components) state data or DOM info, and not model data. For instance if one component needed to ask another component its size, screen position, z-index…?

1 Like

Also interested in this issue. How to communicate between components (Ember way) to exchange some component specific (not model) data.

{{#modal}} {{#button}}Click to close modal{{/button}} {{/modal}}

1 Like

I’m also interested in this issue. The closest thing I’ve been able to find is the idea of a ref helper, but it looks like that’s just an idea and hasn’t been implemented yet (even as a straw man). To put the issue another way, I want to write a reusable addon where sibling addons can somehow communicate DOM state to each other; these are concerns of the component and should not be exposed outside of it. Currently there’s no good way to do this (or if there is, it’s either non-obvious or I am blind).

I agree Ember will need a good answer to this question, but for now I’ve done something like this in the past:

http://www.samselikoff.com/blog/getting-ember-components-to-respond-to-actions/

3 Likes

I’ve been playing around with decorating my ember models as a way to share info that is not persistence related but could still be considered model data. It fills a similar role as the old ObjectController since it holds view related model data as well as persistent model data.

I’m also experimenting with using the same object to do events by registering what I’m listening for on didInsertElement. The object then behaves sort of like an event channel in addition to all the state info required.

1 Like

I’m changing controller properties from one component, but an identical sibling component is not updating.

edit: my issue was that I didn’t have proper strings as arguments in my .property() call

This should already be possible via walking childViews

Also, I think the same approach from React applies here. You would have a “container” component which is a high order component wrapping your two components that you want interfacing which each other via passing down props. This container would broker the notifications to the children. This closely adheres to actions up/data down.

That said, I think after two non-container components talking directly to each other would be an anti-pattern. As they’re meant to be “dumb components” and you would be introduce a strong coupling in trying to do so.

Check out this conversation

@ef4 gave an excellent answer to how this can be done.

With the removal of controllers and the new component emphasis, I find I had to drill it into myself that I cannot just create a property in the router and have the template access it, that it has to be in the model. I knew this, just the controller convenience kept pulling me back into the old habit.

So I found myself wanting to have a change in one component update another component. e.g type in a search query in one component, but then have the paginator #link-to in another component also be able to send this same search query in as you go from page to page. So essentially the search component needed to give the paginator component the search query.

Only 3 ways I could get it to work was:

  • I have a route that includes the search query in the url, then the search box would, on the keyup event, say, do a sendAction from the component back to router, which in turn transitioned to the same router but with a search_term query param change. Then in afterModel(): setting the new property (searchTerm, say) in the model so that the #link-to’s in the paginator component, that is mapped to this same model property (searchTerm) will be updated.

  • More elegant I found, but still a hack, was to return back the search query in meta data (in Ember Data) that both components would have access to (assuming they are within the same router template) {e.g {model.meta.searchTerm}}

  • If your component change does not re-transition the route, then I suppose changing the current model’s property (one that in bound in some way to the other component) would also work.

I must admit I did not like being forced to use either of these two methods. Did anyone have components talk in a different way?

I don’t yet have a great pattern, but the following seems reasonable: given two components which are displayed in the same template and need to share some data, add a third component which is a container. Component 1 sends an action with the relevant data. At this point, you have a choice:

  1. The container component receives the action and sets a property on itself. Component 2 can then see this property.
  2. The container component receives the action and sets a property on component 2.

Neither choice is great and I’m left wondering why I can’t just have a controller container for free, but these should both work.

1 Like

Based on the comments above, i have a page(route) with two components, in first component i have a date control, change on the date , the grid data in the 2nd component should refreshed. In the 2nd component i used ember-light-table to bind the grid data. currently what i have done

  1. component1: on selecting the date , i am sending action to router and setting the selected properties for current date selected.
  2. Then passing that properties to 2nd component{{ daily-task/showroom-visit selectedDate=selectedDate}}
  3. Inside 2nd component reading that property and calling the api to load my grid based on selection.

First time it worked fine, but 2nd time when i change the date in component 1 the 2nd component grid won’t refreshed How to handle this ? if my property value selectedDate change in component 1 then component 2 grid should refreshed. thanks,

If it’s only working the first time that suggests that although you have used binding, the dependency has not been updated on a change.

e.g I think a computed property only gets called if one of it’s dependents have changed from the last time it was called and something called this.get(). So maybe you have got the binding set up but perhaps however you state what the dependent variables are is not correct. Or maybe the dependent variables ARE stated correctly but the value being changed is somehow not one of them.

I am writing this blindly as I have no used ember-light-table before nor is there any code to look at in your post.