Accessing Ember component scope from block form? - ember.js

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.

Related

What is the best way for all instances of an Ember component to share a variable?

I have an Ember component which is essentially a panel. There can be multiple instances of this panel on a page, but only one can be "active" at any given time. Each instance of the component must be aware if any of the other panels become "active" so they can remove their "active" state. I would really rather not move the JavaScript to make this happen to a parent component. Instead, I would like to keep it within this component. In Angular, I used to use a static variable to do this. What is best way to do this in Ember?
I would really rather not move the JavaScript to make this happen to a
parent component
Do you want to avoid having the parent component dealing with anything related to panel "activity"? If so, why?* If not:
Ember automatically gives each component's tag (unless it's a tagless component) an id that is accessible from the js code as elementId. You could create a property activePanelId on the parent component and pass it to all panels: {{pa-nel activePanelId=activePanelId}} and then check in each panel
{{#if (eq elementId activePanelId)}}
{{!whatever is different on the active panel}}
{{/if}}
or use it in the js code:
isActive: Ember.computed('activePanelId', function() {
return this.get('activePanelId')===this.get('elementId');
},
If the panel becomes active by an action related to itself (e.g. clicking on it), just set activePanelId to the elementId in the respective action - since the property activePanelId exists only once on the parent component, all other panels to which it is passed will take note.
If using the elementId feels to hacky, you might as well give each panel a distinct name and store the activePanelName in the calling component.
*If you really do not want the property in the parent component, you could move it to a service that you then inject into the panel components, but I cannot yet imagine a good reason for preferring that.
#arne.b 's anwser sums it pretty well, the best way of handling component's state with common parent data, but if you are dead serious about not using a parent component there is kind of way to get it done.
Example:
import Ember from 'ember';
export default Ember.Component.extend({
sharedObject: {},
sharedArray: [],
});
In the above component you can use sharedObject or sharedArray to exchange state with multiple instances of the component. Any changes in the object or array will be reflected to all the instances of the same component.
A sample Ember 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

Proper way to pass a controller to a Component

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.

itemViewClassBinding in a collectionView

I'm trying to create a reusable component which consist of a textfield and under the textfield, i want to have a collectionView to display a filtered list of elements.
My problem is that I want itemViewClass of the containerView to be customized when creating the component. Currently, I pass a parameter listItemView to the container view and declare
itemViewClassBinding: 'parentView.listItemView' instead of having an hardcoded templates.
This leads me to a problem where Ember assert that itemViewClass must be an instance of Ember.View:
Uncaught Error: assertion failed: itemViewClass must be a subclass of
Ember.View, not function () {
Did anybody ran into a similar problem?
Thank you
Sub-classing your ContainerView class is one option. Here is an example: http://jsfiddle.net/ethan_selzer/kcjzw/240/
This pastie may be a little easier to read: http://pastie.org/4256407
Ethan
I have created this functionality very recently in my ember app. The way I did it was by binding to a controller property. When the user types in the textfield it needs to set the filter text as a controller property. Then your controller will have another property that observes the filter field text property and produces a filtered list of the content data based on the filter text. Then your filtered view would be bound to that filtered content of the controller instead of the usual (all) content. This way your two views don't need to know about each other and the controller provides the data.