Reputation: 2300
I have the following two models:
App.Child = DS.Model.extend({
name: DS.attr('string')
});
And:
App.Activity = DS.Model.extend({
children: DS.hasMany('child',{async:true}),
name: DS.attr('string')
});
I want to use checkboxes to choose between the existing children, for the hasMany relation.
For example, I have these three children:
App.Child.FIXTURES = [
{ id: 1, name: 'Brian' },
{ id: 2, name: 'Michael' },
{ id: 3, name: 'James' }
];
The user should be able to use checkboxes, while creating or editing an activity, for choosing which children, to add to the hasMany relation.
I've created a JSFiddle to illustrate my question: http://jsfiddle.net/Dd6Wh/. Click 'Create a new activity' to see what I'm trying to do.
Basically it's the same as Ember.Select [ ... ] multiple="true", but for checkboxes.
What's the correct approach for something like this with Ember.js?
Upvotes: 5
Views: 2615
Reputation: 19128
You can use an itemController
in your each
view helper to manage the selection. In the code below I created one called ChildController
:
App.ChildController = Ember.ObjectController.extend({
selected: function() {
var activity = this.get('content');
var children = this.get('parentController.children');
return children.contains(activity);
}.property(),
selectedChanged: function() {
var activity = this.get('content');
var children = this.get('parentController.children');
if (this.get('selected')) {
children.pushObject(activity);
} else {
children.removeObject(activity);
}
}.observes('selected')
});
With a itemController you can expose some properties and logics, without add it directlly to your models. In that case the selected
computed property and the selectedChanged
observer.
In your template, you can bind the selection using checkedBinding="selected"
. Because the itemController proxy each model, the selected
property of the itemcontroller will be used, and the {{name}}
binding, will lookup the name property of the model:
<script type="text/x-handlebars" data-template-name="activities/new">
<h1>Create a new activity</h1>
{{#each childList itemController="child"}}
<label>
{{view Ember.Checkbox checkedBinding="selected"}}
{{name}}
</label><br />
{{/each}}
{{view Ember.TextField valueBinding="name"}}
<button {{action create}}>Create</button>
</script>
The same aproach in edit template:
<script type="text/x-handlebars" data-template-name="activities/edit">
<h1>Edit an activity</h1>
{{#each childList itemController="child"}}
<label>
{{view Ember.Checkbox checkedBinding="selected"}}
{{name}}
</label><br />
{{/each}}
{{view Ember.TextField valueBinding="name"}}
<button {{action update}}>Update</button>
</script>
This is a fiddle with this working http://jsfiddle.net/marciojunior/8EjRk/
Component version
Template
<script type="text/x-handlebars" data-template-name="components/checkbox-select">
{{#each elements itemController="checkboxItem"}}
<label>
{{view Ember.Checkbox checkedBinding="selected"}}
{{label}}
</label><br />
{{/each}}
</script>
Javascript
App.CheckboxSelectComponent = Ember.Component.extend({
/* The property to be used as label */
labelPath: null,
/* The model */
model: null,
/* The has many property from the model */
propertyPath: null,
/* All possible elements, to be selected */
elements: null,
elementsOfProperty: function() {
return this.get('model.' + this.get('propertyPath'));
}.property()
});
App.CheckboxItemController = Ember.ObjectController.extend({
selected: function() {
var activity = this.get('content');
var children = this.get('parentController.elementsOfProperty');
return children.contains(activity);
}.property(),
label: function() {
return this.get('model.' + this.get('parentController.labelPath'));
}.property(),
selectedChanged: function() {
var activity = this.get('content');
var children = this.get('parentController.elementsOfProperty');
if (this.get('selected')) {
children.pushObject(activity);
} else {
children.removeObject(activity);
}
}.observes('selected')
});
Updated fiddle http://jsfiddle.net/mgLr8/14/
I hope it helps
Upvotes: 14