Proper way to pass a controller to a Component - ember.js

Ok, I'm trying to get at a computed property on a random controller (not my template's default controller) to pass this property into a component on a random template. With some help on irc I was pointed to: "http://emberjs.com/guides/controllers/dependencies-between-controllers/" and realized my question was more of a controller dependency question than a component question, this helped but I'm still having issues.
So on my blah template's default controller (BlahController) I use the 'needs' hook to get access to the FooBarController like this:
needs: 'foo_bar'
And in the same blah template where I'm calling my component, I get at the FooBarController's property like such:
{{my-widget someProperty=controllers.foo_bar.someProperty}}
And my component just displays the property like such:
{{someProperty}}
The property (someProperty) I'm trying to access is a computed property with it's own dependancies. I get an error that the dependent properties on the computed property don't seem to be available???

Ember components are to be only used when you need completely isolated views to build re-usable ui elements. So, all content that a component needs for its template must be passed in when you invoke the component as parameters. A component should not be bound to a controller. Instead, when it needs to propagate events, it should use the 'sendAction' api to whichever controller controls the template it is invoked in. What you really need is a view.

Related

Ember - Extending {{component}} helper

What I want to do is to pass a string to {{component}} helper, but I want more control over what string it gets passed in at runtime.
e.g.
// getComponentToRender will get the current UI theme in the app,
// determine whether it's running on the mobile mode, then fetches the
// appropriate name of a component to render based on the type of the
// component. Just an example.
{{component getComponentToRender(ComponentType.Button)}}
I investigated this, it turns out this isn't possible (Otherwise, please correct me). Of course, there's computed property, but it doesn't take an argument.
Next, I looked into extending the helper. This stackoverflow question shows you can extend one, but I couldn't locate where the component helper is located in Ember. There doesn't seem to be any questions/documentation regarding extending existing helpers, either. This is what I would do with this approach.
// I can't find where the {{component}} helper is located.
import Component from './???'
export default Component.extend({
compute(componentType, hash) {
let componentName = getComponentToRender(componentType);
this._super(componentName, hash)
}
})
What did I miss? It'd be great if someone can put me into the right direction.
The only way of calling a function from a template is writing an helper. Actually your reference StackOverflow question is also mentioning about helpers. Writing an helper will solve your problem.
You don't need to extend the component helper. You need to compose it. As following:
{{component (getComponentToRender ComponentType.Button)}}
Here is the working twiddle.

Assertion error Using {{controller}} removed in ember 2.0. How to pass/wrap controller object to component

In ember 2.0, I am not able to wrap controller in my-component. it is showing compilation error.
Assertion Failed: Using {{controller}} or any path based on it has been removed in Ember 2.0.
{{my-component ctrl=controller}}
How to achieve this ?. please guide me for alternative solution.
You should use component actions which bubble to controller or passing controller properties in template declaration, if you need to access data from controller, instead of using {{controller}} directive.
You just shouldn't do that. You should only pass in the properties that are relevant for the component instead of the whole controller.
For example if your component needs the properties foo and bar that are defined in the controller than you have to add them to your component call like {{my-component componentAttribute=foo anotherAttribute=bar}}. If you have to use the properties in some nested components you have to pass the properties in the most top level component and then pass it down to the component you want to make use of them.

Sending parameter to a component property

I understand how to send parameters along with an action to a component:
http://emberjs.com/guides/components/sending-actions-from-components-to-your-application/
Is there a way to send parameters to a component's property?
Example: In a template, I'm rendering a component inside an each loop. The loop is iterating through the various instances of the model of the array controller. I would like to pass the individual instance of the model of the array controller to a property of the component. The property is a function that will create a chart base on the value of the passed instance of the model. The chart needs to be created in JavaScript. Any way to achieve this?
If I understand what you are asking - this is actually very easy to accomplish:
http://emberjs.com/guides/components/passing-properties-to-a-component/
So, something like the following:
{{ your-component propertyInComponent=modelInstance }}
Then, in your propertyInComponent which is defined in your component's js file is yours to do whatever you want with it.
I would pass in the model as a regular property and then call the chart creating function on the didInsertElement event.
http://emberjs.com/api/classes/Ember.Component.html#event_didInsertElement

Accessing Ember component scope from block form?

I want to let a user pass a custom text field, App.CustomTextField, in a Ember component using block form. However, that App.CustomTextField needs access to the component to manipulate its properties. How can I pass the component to the textfield using block form? I would like to pass the component as a property to App.CustomTextField, but how do I access the component's scope?
{{#blog-post}}
{{view App.CustomTextField component=?}}
{{/blog-post}}
The approach you are taking is not a very good idea. Components should expose properties. They are sort of like external settings that specify the component's behaviour.
Simply convert App.CustomTextField into a component and set all the required properties on it.

accessing the model from the template

Playing around with ember, I found that sometimes the model is stored on the controller's content property, sometimes the model is directly available on the controller as well. I do not understand however, when this is the case.
Let me explain it by an example which I found when assembling my ember MVC.
Setup A - The start
I defined a custom Member object, corresponding MemberRoute, MemberView classes and a template with the name member.
The Member object had some attributes such as id, nickname, etc.
NOTE: no controller of the form MemberController was defined, thus by ember's convention, it provides the controller on its own.
Setup B - The customization
Same as setup A, but now there is a MemberController defined that contains some action methods that are triggered from within the template.
The strange behaviour (resp. what I do not completely understand)
in setup A, I can refer to the Member's attributes directly with {{id}} or {{nickname}}.
in setup B, I have to use {{content.id}} or {{content.nickname}}
As documented in ember's documentation, MemberView does
setupController : function(controller, member) {
controller.set('content', member);
},
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
Any help to understand this is highly appreciated. It already took my quite a while to come as far as this. I first thought it could be the modularization introduced by the project setup with requireJS (well, I still think that could have a influence). Ember is v1.0pre4.
Thanks in advance!
Patrick
So, could somebody help me to understand why the difference and where the difference is? Currently, my guess would be either
that the context of the template is different (possibly there is a code piece missing in the setup of the controller?)
or
the default controller that is provided by ember automatically, has some additional magic that is not directly avaiable for customized controllers.
It's hard to say for sure without seeing your code, but my best guess is that your MemberController extends Ember.Controller. The default provided by ember (in this scenario) would have been an Ember.ObjectController. If that's what you want, change your MemberController definition to:
App.MemberController = Ember.ObjectController.extend({
myProperty: 'value'
});
An objectController acts as a proxy to it's content property, typically that is an ember model. So if things are wired up correctly you should never need to access a model via the 'content` property. If you ever see something like:
{{content.id}} or {{content.nickname}}
it's a sign that you should change to an ObjectController. See EMBER GUIDES: REPRESENTING A SINGLE MODEL! for a more detailed explanation.
an ObjectController acts as proxy to the object set to the controller's content. When no controller is defined, Ember will create a controller for you and set its content by default to whatever object is returned by the model() function, if defined, in the route. The behaviour should be the same whether you define your own controller or let Ember define one for you
The default context in the template is the controller itself i.e. this = an instance of your controller or the generated one. When you try to access nickname in that context, Ember will first try to resolve it against the controller itself and if nothing is found, it resolves it against its content, i.e the object if you already manually set it to the controller's content.
Finally, there is no default implementation of the model() function in the Route except when you're using dynamic urls, say /foo/id that resolves against /foo/:id, Ember uses the id provided to load a Foo object with the id provided, thus providing a default implementation to the model() function. At the end it boils down to the same mechanism, only automated for your convenience.
I suggest you listen to this for more insights on how things are automated for you by Ember. But when it comes to the content being displayed, there is no magic you have to manually wire the content of the controller.