Series: Ember Actions

Action Bubbling

Published on Sep 11, 2015

Actions aren't just on controllers- they're also on routes (and, as we'll see next time, on components).

In this video we discover how actions bubble up the route hierarchy, and explore methods you can use to block or propagate an action after catching it.

We also look at action bubbling on the DOM and the 'send' method.


Links

Code

Action bubbling happens from the controller to the parent route, to it's parent route, up until you reach the application route.

Returning true (or not having a named action on the controller/route in question) will bubble it up. You can

actions: {
  takeOffHat(){
    this.set('hasHat', false)
    return true
  }
}

You can also send it to a specific action with send

actions: {
  putOnHat(color){
    this.set('hatColor', color)
    this.set('hasHat', true)
    this.send('pressRelease')
  }
}

Finally, you can set bubbles=false in an action helper to stop DOM event bubbling (different than the action bubbling in the previous two examples)

<button {{action 'takeOffHat'}}>Take off the hat <button {{action 'howToRemoveHat' bubbles=false}}>How?</button></button>

Transcript

Hi and welcome back to EmberScreencasts. Today we’re going to be talking about action bubbling. Last time we learned how to attached actions to HTML elements. So in this case we’re clicking the button, and then we’re sending an action, putOnHat, to the controller. And this action takes a parameter. So user clicks, something happens.

But the controller isn’t the only place we can put an action. We can put it in a component as we’ll see next week and we can put it in a route. Let’s show that off. So here we’re going to add another button that calls the action pressRelease. Then we’re going to go to our route and add the action pressRelease. Here we’ll see that when we trigger that action, the action on the route catches it. So this example was very cut and dried because there’s an action pressRelease on the route but there’s no action pressRelease on the controller. What happens if we have a putOnHat action on the route? Let’s find out. We see that it only fires the first action, the one on the controller. It never gets to our action on the route. This is because of action bubbling.

So when you trigger an action on a non-component action, it’ll go first to the controller. Then if the controller doesn’t have an action for it, it’ll go to the associated route. If that doesn’t have an action, then it’ll go to the parent route and the parent route until it gets to application route. The action trigger will stop bubbling whenever an action has been defined that can catch it. However, there are ways to keep bubbling even if you’ve already caught that action.

One way to do this is to return true from that action. When we trigger takeOffHat, it will trigger the controller, and then because it returns true, it will trigger the takeOffHat on the route as well, so both takes off the hat and shows the alert.

So this is the way that actions bubble by default. However, there’s a way to catch the actions and send them along a different route using the send method. So if we decided that after the user put on the hat they weren’t getting marketed to enough, we can call this.send and then the name of the action pressRelease. This action isn’t on the controller, so it’ll bubble up to the route. There we go. We sent that action.

So there are three ways you can bubble up. One is naturally. If the action isn’t defined in the case of pressRelease here then it’ll bubble up to the next place, in this case route. If you return true from an action that you have defined, then it will keep bubbling, even though defining an action would normally stop the bubbling. And if you call send, then it will redirect to a different action bubbling line.

So those are the three ways of bubbling up, but we’re not quite done yet. One more thing before we go. Let’s say we put another button in here and takeOffHat, and this button also had an action. So if we click this button, then it will trigger both of these actions. We’ll define this action in our controller, and then we’ll see it in action on the page. So first it triggers the one from help button, and then it triggers the one from the surrounding button.

We only want to trigger the help button. We’ll do this with the bubbles=false. So there’s a separate type of bubbling that will bubble from this element to the surrounding elements. It operates according to a different mechanism as the controller and route bubbling, but it’s still relevant. So now when we hit ‘Help’, it only shows the correct thing, and we can still hit the other one and it’ll do what it did before.

So that’s action bubbling. We learned about how actions bubble up through the route hierarchy in Ember, several ways to mess with that, and then a little bit of HTML event bubbling. I hope this helped you out and I’ll see you next week when we talk about actions and components and closure actions.

Ember Actions

Subscribe to our mailing list