Ember send() and sendAction()

Some of us might find the use of send and sendAction in Ember components a bit confusing. I would try to explain how send and sendActions communicate with controllers and routes, with some examples of common pitfalls you might encounter.

Let’s assume we have the following cases to handle:

  1. Passing data from a component to its controller/route.
  2. Passing data from a controller to its route.
  3. Passing data from a nested component to its parent component.

Ember follows a convention called “Data Down Actions Up” or famously the DDAU approach. What does that mean? Well, in simple words, we have to send data down and trigger actions up.

From the basics of working with Ember, we know it’s router.js which is the entry point to identify which route/controller/template is to be invoked.

Let’s assume, we have a route called foo.show. Our router file is routes/foo/show.js and if needed a controller in the same naming convention controllers/foo/show.js. When a route is created (via ember g), Ember CLI also creates a template in the path templates/foo/show.hbs. Let’s say we have a component called {{foo-bar}} that will be rendered inside our show.hbs template. This is how our project structure would look like

On the left is our project folder and on the right is the Router.js configuration.

1. Passing data from a component to its controller/route:

When you want to communicate from a component to its controller/route, you simply call sendAction(). Remember! sendAction() can be used from a component but not from controllers/routes.

// component/foo-bar.js
export default Ember.Component.extend({
actions: {
sendDataToController() {
this.sendAction('sendData', 1);
}
}
});
// controllers/foo/show.js
export default Ember.Controller.extend({
actions: {
sendData(data) {
alert(data);
}
}
});
// routes/foo/show.js
export default Ember.Route.extend({
});
NOTE: If you want to trigger an action in a route from a component, you can just do the same code as above, in which case the controller needn’t have the action.
// component/foo-bar.js
export default Ember.Component.extend({
actions: {
sendDataToController() {
this.sendAction('sendData', 1);
}
}
});
// controllers/foo/show.js
export default Ember.Controller.extend({
});
// routes/foo/show.js
export default Ember.Route.extend({
actions: {
sendData(data) {
alert(data);
}
}
});

Check out the Github GIST and Ember twiddle here.


2. Passing data from a controller to its route.

When you want to communicate from a controller to its route, you simply call send() . Here sendAction() will not work!

// component/foo-bar.js
export default Ember.Component.extend({
actions: {
sendDataToController() {
this.sendAction('sendData', 1);
}
}
});
// controllers/foo/show.js
export default Ember.Controller.extend({
actions: {
sendData(data) {
alert("Data is sent to controller as " + data + ". Will now send to route");
this.send('sendDataToRoute', data);
}
}
});
// routes/foo/show.js
export default Ember.Route.extend({
actions: {
sendDataToRoute(data) {
alert("Data sent to route" + data);
}
}
});

But the above doesn’t make sense as the actions not present in Controller would internally propagate to its route.

// component/foo-bar.js
export default Ember.Component.extend({
actions: {
sendDataToController() {
this.sendAction('sendData', 1);
}
}
});
// controllers/foo/show.js
export default Ember.Controller.extend({
// Can remove this actions.
  actions: {
sendData(data) {
alert("Data is sent to controller as " + data + ". Will now send to route");
return true;
}
}
});
// routes/foo/show.js
export default Ember.Route.extend({
actions: {
sendData(data) {
alert("Data sent to route" + data);
}
}
});
NOTE: When you communicate from a controller to its route, the mantra is to simply call this.send().

Check out the Github GIST and Ember twiddle here.


3. Passing data from a nested component to its parent component.

When you want to communicate from a component to its parent component, then the call to be used is sendAction().

// templates/foo-bar.hbs
{{foo-bar-2 sendDataToParent='sendDataToParent'}}
// component/foo-bar.js
export default Ember.Component.extend({
actions: {
sendDataToParent(data) {
alert('Data received ' + data);
}
}
});
// component/foo-bar2.js
export default Ember.Component.extend({
actions: {
sendDataToParent() {
this.sendAction('sendDataToParent', 1);
}
}
});

What if you want to trigger an action in its route?

All you need to do is simply follow Step 2. But there is an Ember add-on to do this for you, which will propagate your action from foo-bar2 to routes/foo-bar/show.js route called ember-route-actions-helper.

NOTE: If you wish to trigger an action in foo-bar2 itself, then you call this.send() and not this.sendAction()

Check out the Github GIST and Ember twiddle here.


Thanks to vivekanandan and Pavan Madhusoodanan for the edits.

If you like this post or find anything misleading, do post your comments!