How to bind value form input select to attribute in controller
Solution 1
Ember now has a built-in Select view.
You can find it in the latest Ember.js build here: http://cloud.github.com/downloads/emberjs/ember.js/ember-latest.js
Here's an example usage:
var App = Ember.Application.create();
App.Person = Ember.Object.extend({
id: null,
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + " " + this.get('lastName');
}.property('firstName', 'lastName').cacheable()
});
App.selectedPersonController = Ember.Object.create({
person: null
});
App.peopleController = Ember.ArrayController.create({
content: [
App.Person.create({id: 1, firstName: 'Yehuda', lastName: 'Katz'}),
App.Person.create({id: 2, firstName: 'Tom', lastName: 'Dale'}),
App.Person.create({id: 3, firstName: 'Peter', lastName: 'Wagenet'}),
App.Person.create({id: 4, firstName: 'Erik', lastName: 'Bryn'})
]
});
Your template would look like:
{{view Ember.Select
contentBinding="App.peopleController"
selectionBinding="App.selectedPersonController.person"
optionLabelPath="content.fullName"
optionValuePath="content.id"}}
Again, here's a jsFiddle example: http://jsfiddle.net/ebryn/zgLCr/
Solution 2
Jumping off from the solution for @pangrantz, this Fiddle example (http://jsfiddle.net/bsyjr/) illustrates some improvements: The Handlebars code is cleaner through the use of tagName. When tagName is set to "select", the child views automatically become "option" elements. See the Ember.CollectionView.CONTAINER_MAP in https://github.com/emberjs/ember.js/blob/master/packages/ember-views/lib/views/collection_view.js to understand why. On the Javascript side, by specifying an itemViewClass, we can add the value attribute to the option element.
<script type="text/x-handlebars" >
{{#collection Food.SelectView tagName="select" contentBinding="Food.foodController"
valueBinding="Food.appsController.selectedValue"}}
{{content.title}}
{{/collection}}
selected: {{view Ember.TextField valueBinding="Food.appsController.selectedValue"}}{{Food.appsController.selectedValue}}
</script>
Food = Ember.Application.create();
Food.SelectView = Ember.CollectionView.extend({
value: null,
itemViewClass: SC.View.extend({
attributeBindings:['value'],
valueBinding: 'content.value'
}),
valueChanged: function(){
this.$().val( this.get('value') );
}.observes('value'),
didInsertElement: function(){
var self = this;
this.$().change(function(){
var val = $('select option:selected').val();
self.set('value', val);
});
}
});
Food.appsController = Ember.Object.create({
selectedValue: ""
});
Food.Todo = Ember.Object.extend({
title: null,
value: null
});
Food.foodController = Ember.ArrayProxy.create({
content: []
});
Food.foodController.pushObject(Food.Todo.create({title:"a", value:"1"}));
Food.foodController.pushObject(Food.Todo.create({title:"b", value:"2"}));
Food.foodController.pushObject(Food.Todo.create({title:"c", value:"3"}));
There is still room for improvement in the event handling, which is not using Ember's event framework, and it would make a lot of sense to use a custom written SelectView that doesn't leverage Handlebars, since IMO, it is dubious how much value Handlebars adds in this case.
Solution 3
Using a custom Ember.View works for me, but I think there is a better solution...
See working example is this fiddle http://jsfiddle.net/pangratz/hcxrJ/
Handlebars:
{{#view Food.SelectView contentBinding="Food.foodController"
valueBinding="Food.appsController.selectedValue"}}
<select>
{{#each content}}
<option {{bindAttr value="value"}} >{{title}}</option>
{{/each}}
</select>
{{/view}}
app.js:
Food = Ember.Application.create();
Food.SelectView = Ember.View.extend({
value: null,
valueChanged: function(){
this.$('select').val( this.get('value') );
}.observes('value'),
didInsertElement: function(){
var self = this;
this.$('select').change(function(){
var val = $('select option:selected').val();
self.set('value', val);
});
}
});
Food.appsController = Ember.Object.create({
selectedValue: ""
});
Food.Todo = Ember.Object.extend({
title: null,
value: null
});
Food.foodController = Ember.ArrayProxy.create({
content: []
});
Food.foodController.pushObject(Food.Todo.create({title:"a", value:"1"}));
Food.foodController.pushObject(Food.Todo.create({title:"b", value:"2"}));
Food.foodController.pushObject(Food.Todo.create({title:"c", value:"3"}));
Solution 4
I'm not sure if this is of use to others, but I've been doing something similar based on the answers here, and have made this SelectView that should work in this context too. It binds to 'change', works out the view that is currently selected and then does something with its content.
Food.SelectView = Ember.CollectionView.extend({
change: function(e) {
var selected = this.$().find(":selected").index();
var content = this.get('childViews')[selected].content;
// Do something with the result
Food.appsController.set('selectedValue', content.title);
}
});
This way you're able to pass around an object rather than the index of the select.
Bank
Updated on June 26, 2022Comments
-
Bank almost 2 years
I try to bind value from input select to attribute "selectedValue" in controller.
This is app.js
Food = Ember.Application.create(); Food.appsController = Ember.Object.create({ selectedValue: "" }); Food.Todo = Ember.Object.extend({ title: null, value: null }); Food.FoodController = Ember.ArrayProxy.create({ content: [] }); Food.FoodController.pushObject(Food.Todo.create({title:"a", value:"1"})); Food.FoodController.pushObject(Food.Todo.create({title:"b", value:"2"})); Food.FoodController.pushObject(Food.Todo.create({title:"c", value:"3"}));
This is index.html
{{#collection contentBinding="Todos.todosController" tagName="select" itemClassBinding="content.isDone"}} {{content.title}} {{/collection}}
Output look like this
<select id="ember180" class="ember-view"> <option id="ember192" class="ember-view"> <script id="metamorph-0-start" type="text/x-placeholder"></script> a <script id="metamorph-0-end" type="text/x-placeholder"></script> </option> <option id="ember196" class="ember-view"> <script id="metamorph-1-start" type="text/x-placeholder"></script> b <script id="metamorph-1-end" type="text/x-placeholder"></script> </option> <option id="ember200" class="ember-view"> <script id="metamorph-2-start" type="text/x-placeholder"></script> c <script id="metamorph-2-end" type="text/x-placeholder"></script> </option> </select>
I have no idea how to add value to option and how to binding selected value back to controller. Is this possible to do in Emberjs?
-
Peter Wagenet over 12 yearsIt's worth noting that the
{{#collection}}
helper is deprecated as the same results can be achieved with greater clarity using{{#each}}
as @pangratz did. -
Bank over 12 yearsshould add this view to Ember core :-)
-
ebryn over 12 yearsI've got an improved version that will be included with Ember soon: github.com/emberjs/ember.js/pull/424
-
Peter Wagenet about 12 yearsTo provide further clarification, there are still some places where
{{#collection}}
is useful. However, I would try using{{#each}}
first and if it you aren't able to get the results you want then consider{{#collection}}
we plan to make further improvements to{{#each}}
which will cover more cases. -
Visionscaper almost 12 yearsThis solution works well for me for multiple reasons: a) The Ember.Select view gives back the whole object in the content array as selected value, while I'm only interested to get back the actual select value. b) For what I'm working on this implementation is much faster: I don't need bindings on the labels and values, they don't change (I removed the valueChanged method in the view class extension above since I didn't need it) Final remark : the select change handler method contains a small error (when you have multiple selectors): $('select options... should be self.$('select options...
-
HaoQi Li almost 11 yearsbtw, this is the Ember.Select api
-
Patrick M about 10 years
-
Mike almost 9 years
Ember.Select
is now deprecated. What is the updated way to do this?