Actions in routes


#1

Hi,

I had started a habit of putting actions in routes instead of the controller, but found that randomly it throws errors in some cases, complaining the action isn’t found in the controller.

EmberError {stack: “Error: Assertion Failed: An action named 'fontChan…0/roomviewer-tradehelp/assets/vendor.js:18479:39)”, description: undefined, fileName: undefined, lineNumber: undefined, message: “Assertion Failed: An action named ‘fontChanged’ wa…adehelp@controller:user/planner/edtext::ember706>”, …}code: undefineddescription: undefinedfileName: undefinedlineNumber: undefinedmessage: "Assertion Failed: An action named ‘fontChanged’ was not found in <ember-roomviewer-tradehelp@controller:user/planner/edtext::ember706>"name: "Error"number: undefinedstack: "Error: Assertion Failed: An action named ‘fontChanged’ was not found in <ember-roomviewer-tradehelp@controller:user/planner/edtext::ember706>↵ at new EmberError (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:24127:25)↵ at assert (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:24370:15)↵ at makeClosureAction (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:28714:50)↵ at exports.default (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:28395:12)↵ at http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:11949:21↵ at AppendOpcodes.evaluate (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:11725:13)↵ at VM.next (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:18901:32)↵ at VM.execute (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:18887:31)↵ at TryOpcode.handleException (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:18286:16)↵ at UpdatingVMFrame.handleException (http://localhost:4200/roomviewer-tradehelp/assets/vendor.js:18479:39)"proto: ExtendableBuiltin

Is this intended? The action exists in the router instead. Some of the other actions on the page are fine.

Thanks for any suggestions


#2

I’m not sure why it would fail intermittently. Perhaps the asynchronous routing? One approach to do this explicitly is set a property on your controller that references the route:

// this is a routing hook that should go in your routes
setupController(controller) {
   controller.set('currentRoute', this);
}

From a route’s template, you can then configure the action helper’s target option:

{{my-component someAction=(action 'onRoute' target=currentRoute)

Though this kind of suggestion should be taken with caution. As an aside, I remember reading a chart demonstrating the event flow of actions throughout an application. Something like this would be helpful to better explain what is going on here.


#3

Could it be that the not-found-in-controller errors are coming from calling the action from a component, while the others that are found are being called from a template?

If so, I think components can only reference actions that live in controllers, not routes. Here is a discussion related to that same topic: Calling route action from a component fails


#4

In this case it is not in a component. It is in a template directly belonging to the route. It is a select box change event. Maybe there is something special about this type of event that it has to be in the controller.


#5

I see what you mean, but it bugs me that I have to find my own workarounds for something that is really supposed to work.


#6

certainly is frustrating! I remember seeing a diagram that depicted actions bubbling through an ember application. It seems one could help here to clarify the expected behavior.


#7

Where it doesn’t work, you’re probably using closure actions in which case the referred action is looked up in the context of the template. The context is the controller in case of “route-driven” templates and the component in the case of component templates. Closure actions don’t bubble: if they’re not found in the context of the template, the error you pasted is thrown.

Example of a closure action: <button onclick={{action "updateRating"}}>

Where it works, you probably use a “string” action, where only a string is passed, like

{{user-form save="saveUser"}}

This is definitely a complicated area in Ember.js, here are a few resources that might help:


#8

Thanks a lot for weighing in on this, Balint.

BTW, I have both of your Ember books (v2 and v3) and like them a lot. If anyone else ends up here I highly recommend checking them out:

Rock And Roll With Ember JS


#9

I always use ember-route-action-helper for this cases. It’s working quite nicely and also documents if the action is defined in Controller or Route.


#10

Hey Larry,

I’m only seeing this now, but each new happy reader I learn about makes me happy, so thank you!