Also of note, if you are an intermediary component and are just passing along the action to your parent you do not have to use {{action "someName}} at all, you would just bind to the action you were provided from your parent. This makes it SUPER clear where this thing is coming from in the template (and removes silly boilerplate from your components just to “bubble” an action).
<!-- some top level template -->
<some-middleman on-selected={{action "onSelectChange"}}>
This is just a little example, and not knowing anything about ReactJS, it doesn’t seem that this example is totally “data down”. If you make a change to the isSelected property of the model it doesn’t reflect itself in the checkbox in the selectable-item.
Using this approach, how would you make changing the model check or uncheck the checkbox?
Ah you’re right, it should be checked=item.isSelected, but then every time you click a checkbox, both the {{input}} helper and the action handler in the parent component toggle the property.
What you’d need is for {{input}} to be one-way, so it’d be something like
so that when the user clicks, the action essentially goes straight to the handler (from the parent), which then updates the isSelected property, which then propagates the change back down to the checkbox.
I know this is a silly little example, but I’m learning about Ember, and I am trying to understand how things work.
I updated the original jsbin to use bind-attr like you mentioned, and added a one-way binding from the model’s isSelected to the selectable-item’s isSelected, to link those together:
The checkbox doesn’t toggle at all now, even though the selectable-item’s isSelected property is being toggled via the one-way binding.
I like seeing a working example of this concept. Like you said in a post above, it seems that two-way bindings are useful in these types of nitty-gritty cases (binding for form elements), but using data bindings from top to bottom in your application might be a bad idea.
I’d love to hear what the recommended pattern for this is. In our app, we have a few itemControllers that are really “helpers” for things like action handling and CP data transformation. They end up with a lot of reuse through out the app, but have different markup. Something like this:
{{#each user in loggedInUsers itemController="user"}}
<label>Name:</label> {{user.displayName}}
<label>Last Login:</label> {{user.lastLogin}}
{{/each}}
In the above example, the user item controller has some actions and computed properties that are very frequently reused.
At first, I thought a replacement might look something like this:
{{#each user in loggedInUsers}}
{{#user-widget user=user}}
<label>Name:</label>{{controller.displayName}}
<label>Last Login:</label> {{user.lastLogin}}
{{/user-widget}}
{{/each}}
But that leaves me with a conundrum, how do I access the component scope within the template? {{controller}} doesn’t work, neither does {{view}}. Is there a way to do this? The same goes for action targets as well. Adding an {{action}} to the the user’s displayName will always target the controller for the template’s primary scope, not for the parent component.
So to boil it all down, if each and every user-widget looked the same, I’d just use that. But surely the recommendation isn’t to make 14 different user-widgets, right?
@workmanw My understanding is that block parameters will will solve this shortcoming of components.
{{#each user in loggedInUsers}}
{{#user-widget user=user as |yieldedThing|}}
<label>Name:</label>{{yieldedThing.displayName}}
<label>Last Login:</label> {{user.lastLogin}}
{{/user-widget}}
{{/each}}
I don’t know what that syntax looks like inside of the component. Anyone have more insight?
In the RFC the example with the {{#form-for}} component alludes to this.
Regarding actions, I know you can specify a target now, so I’m thinking you could still specify a target in Ember 2.0, so you could specify your yielded object as the target. All speculation here.
If that is the recommended pattern, I’ll have to wait for block parameters to land before migrating away from itemController. Regardless, I’m happy to see the functionality will be preserved.
Just come across this old issue and I find it interesting: https://github.com/emberjs/ember.js/pull/3424. When you get to nested ArrayControllers this is even hard to do in Components. Wonder what happened to the follow up on the issue?
@amk I’m not sure Embers traditional array controllers should be dealing with view/animation concerns.
Animation makes more sense with components. React has a model for animating components and it took inspiration from Angular. It is certainly something that needs to be considered.
Another thing React provides is access to an opaque children collection of all child components. Something like that may appear in Ember components as well, including the ‘ref’ property for being able to reference children by name.
The obvious pattern to me wrt collections of things and selection state is that the child component should send an action to the parent on select change and let it decide what to do. The parent may have single or multi select semantics and need to manage that. The selected state should be passed down to each child component from the parent.
Wrt to passing state down in the bigger picture immutable data types are built for this kind of thing and allow for very efficient subsetting of data without copying. I’m keen for Ember to give immutable data types some serious consideration as they have many payoffs including keeping the state unidirectional and undo/redo practically for free.
I was also thinking about this problem, my first shot at it is this: GitHub - piotrpalek/co-list: Ember-cli list addon (requires block params). I am curious about your opinion on going down this path, obviously what I’ve done with that list component is basically just an experiment.
This ‘ref’ thing would be great, I’m in need for something like this to pass around references of components that are not in a parent-child relation. Polymer solves this through id=“xxx” and look-ups via normal getElementById() and as it’s DOM only you get the component instance which I think is quite nice.