How to invoke an controller action in ember.js - ember.js

I am rendering charts(based on highcharts) using ember. I want to invoke a function on clicking a point. I have defined this function inside my ember component. See jsfiddle link below:
{} http://jsfiddle.net/qmmvx/67/
On clicking a point, I get an error which indicates App.ChartComponent is null.What is it that I am missing here?

Not sure if using App.__container__.lookup here is the smartest way, but replacing App.ChartComponent.test(); with App.__container__.lookup('component:chart').send('test') solves your problem. send is used to invoke any method from actions.

Related

Ember: Call a component action from a controller

I have a component working pretty well and now I need to call it inside a controller.
Scenario: I have an ember application, and I have an update button controller, I did a component that just display a toast(Materializecss) with some message I pass as parameter to the component and both the button and the toast are working well separately. I need to call inside the button controller this component to display to the user if the update was successfully or not using this component I did. Any sugestion of how can I call this component inside the controller? Thanks
have a look at the ember-twiddle I created and see if it fits the bill, in regards to what you want to do ?
You should instead of thinking "calling the component", rather, how can I push updated attributes/data to the component.
Ember relies on the "Data Dow Actions Up" pattern. This implies that you cannot make an explicit call to a component action from a controller. (see https://dockyard.com/blog/2015/10/14/best-practices-data-down-actions-up for example)
Instead, a better design should be to define a service to manage data : messages to be "toasted". Then make this service available by injecting in in your controller. You will be able to call methods to register a new messages and generate new data.
Provide also a component template (to be included in your own templates) that will be in charge to display the new message, etc. Each change in the data managed by the service will lead to a component template update.
You should definitely take a look to https://www.npmjs.com/package/ember-toastr

Sending Ember Highcharts events back to parent component

I'm using Ember 2.3 and have built a controller around Ember Highcharts. When a chart point is clicked I send that event back to the controller via the following nasty bit of code added to the highcharts configuration object:
Graph.__container__.lookup('controller:accounts.account.outlets.outlet.ratings').send('pointClick', event);
(I know this is fundamentally wrong and should be using getOwner.lookup for the container reference)
This works without issue, but I'm now refactoring this controller to a component and can't think how to pass the graph event back to the component as components are not registered in the app container.
Any pointers to how to achieve this would be very much appreciated!
Thanks.
UPDATE
I've just discovered that I can send an action to a component from the Highcharts event function:
Graph.__container__.lookup('component:ratingsGraph').send('pointClick', event)
But this seems to create a new instance of the component, rather than send to the existing instance. I guess that makes sense as components aren't singletons.
Very frustrating!
Some days you can't see the wood for the trees!
Instead of defining the highcharts event function in the highcharts configuration parameters, I simply defined it within the component and passed it to highcharts. This enabled me to use a closure to hold reference to the defining component.
Doh!

Prevent error of missing handler in controller

How can we normally prevent Nothing handled the action error in generic view implementation.
Currently I am reopening controller class and adding empty handler but again if I put it directly Ember throws deprecation message Action handlers implemented directly on controllers are deprecated if I add it in action object it is "not working" (probably overridden) and throws error as if it is not in base controller. Any ideas? Thanks.
If you want a somewhat hacky way to do it, you can add the method to the _actions object on the controller. That's where Ember internally keeps all of the actions for an object. Unfortunately, there's no other way to really handle an unused action from a view. This issue suggested a feature that would allow you to, but it hasn't been implemented yet.
Personally, I don't use straight views at all, I only use components. Components allow you to subscribe to particular events (let them bubble up) and ignore the others completely.

What is the craic with ContainerViews? (Assertion Failed: calling set on destroyed object)

All,
I have searched around for an answer to this but have yet to find a good explanation and solution. Hopefully, you can help.
I have a route that renders an Ember.ContainerView (as opposed to a standard Ember.View). When I transition away from this route and then back to it (either via the back button, a link-helper or just changing the url) I get the following error in the console:
Uncaught Error: Assertion Failed: calling set on destroyed object
I understand that a high level reason for this is that when we transition away from the route with the ContainerView, it's childViews are marked as destroyed. When we transition back to the route, the problem has something to do with Ember trying to set the childViews back to the destroyed instances.
I'm not exactly clear but that is the vague understanding I currently have.
So, my questions are as follows:
Can you please correct my understanding of this problem if it is not correct?
Can you please tell me how to fix this error?
For your convenience, I have created a JSBin example for your viewing pleasure. To replicate the error, open your JS console, click on the Go to Route two link, then click on the Go to index link. Now check your logs.
Thanks in advance for any assistance you can provide.
Here is the fix: http://jsbin.com/jumoy/1/edit?html,css,js,output
I have encountered this problem before. I can't say I truly understand it at a very detailed level, but here is the general problem. When you are defining your container view, it is actually creating that subview when you define it, not when you create an instance of the view. This means that your childview 'initial' is only being created one time, and thats when the file is initialled parsed and the ContainerView is defined. When ember cleans this childview up, it is not gone for ever and 'initial' will always be equal to a cleaned up view.
By setting 'initial' as a property, it will be created every time a new instance of your container view is rendered, and therefore a new childview will be created and accessible.
So moral of the story, try not to create objects in definitions of controllers/views. Instead create properties that return the creation of that object.
Hope this helps and makes sense.
UPDATE::
I have edited the jsbin to show you on a deeper level what is happening and why it isn't working. To see the effect uncomment the second ContainerView and comment out the first, you will notice in the console logs that the second time you go to the twoRoute, it has marked that initial property as state: destroying for the view.
http://jsbin.com/jumoy/2/edit?html,js,output
if you are using Ember.Instrumentation namespace for publishing your events and Ember.subscribe to listen to them in your code, when you publish events, it stack all the subscribers and call them even when they are destroyed.
so basically, when for example your route is destroyed which is running subscribe statements it will fail and give above error.
Here is a solution to this problem: Use Ember.Instrumentation.reset() to remove previous subscribers which are destroyed. This solution helped me in acceptance tests where app was destroyed after tests are finished.
I wrote Ember.Instrumentation.reset() in startApp function of module-for-acceptance.js and it worked.
Hope that helps.

TransitionTo and the new Ember Router

The new ember router has been throwing me for a loop. Does anyone know how to manually triggering a url change when you are (1) NOT using a redirect in the router (2) NOT using the linkTo helper?
It seems that this:
App.container.lookup('router:main').router
no longer works, as of today's build.
This seems hard to do in new ember router because ember is working hard to prevent you writing code in this style. Rather than access an instance of the router (or anything else) via App your ember application code should be working with properties that have been injected at runtime by the framework. As #sly7_7 mentioned above, your view will have access to the controller and controller can trigger a transition like:
view.get('controller').transitionTo('state')
Depending on how your third party library is working, you might do this by triggering an event in the dom (handled by the view) or by registering a callback when the view is rendered from within didInsertElement
The main thing to remember is that App.anything-in-lowercase is generally bad practice. Whenever possible try to let the framework take care of instantiating and wiring together your application classes.
For more detail, see the notes on this commit: https://github.com/emberjs/ember.js/commit/5becdc4467573f80a5c5dbb51d97c6b9239714a8
You can try this:
App.__container__.lookup('router:main').transitionTo('name_of_your_route');