Select in Ember with multiple selection
25 September 2015
A few weeks ago I wrote a blog post about how to do a select in Ember 2, that seemed to be popular. I also received good comments about advanced versions of the same problem, namely how the solution would have to change to deal with the case if the items to select from are objects and how to tackle multiple selections. I thus decided to do a Part 2, showing a solution for these cases. Comment are welcome, as always.
Multiple selection with simple strings as items
Let's tackle the easier problem first, being able to select more than one items, but the items are simple string values. The values will serve both as the value and the content of the options.
I added some extra Bootstrap markup and a list to see which items are selected:
I added the multiple
attribute to the select
tag to allow multiple selections. Not much has changed from the earlier example. When the user selects an option, whether in a way that clears the earlier selection (simple click) or adds to it (ctrl/cmd + click), the onchange
event is fired, and our selectBand
handler will handle it. We expect that handler to set selectedBands
so that the list of selected bands gets updated correctly. So let's see the controller:
1export default Ember.Controller.extend({ 2 bands: ['Pearl Jam', 'Tool', 'Long Distance Calling', 'Led Zeppelin'], 3 4 selectedBands: [], 5 6 selectedCount: Ember.computed.reads('selectedBands.length'), 7 8 actions: { 9 selectBand(event) { 10 const selectedBands = Ember.$(event.target).val(); 11 this.set('selectedBands', selectedBands || []); 12 } 13 } 14});
For multiple selections, jQuery, aliased as Ember.$
, returns an array of the selected options values as the select's value, so all we have to do is assign this to the selectedBands
property. In case nothing is selected, val()
returns null
, so we guard against transferring this to selectedBands
by defaulting to an empty array.
There is one more thing you might have noticed, and that is the include
helper in the template. We want to mark the option as selected if its value is included in the selectedBands:
The include
helper is not provided by Ember but it is rather easy to write ourselves:
That is all there is to it:
Multiple selection with objects as items
This is just a tad more difficult, as we cannot directly have objects as options values. Let's assume that these objects have a property that identifies them unambiguously (which is a fair assumption to make), usually referred to as id
:
1import Ember from 'ember'; 2 3export default Ember.Controller.extend({ 4 bands: [ 5 Ember.Object.create({ id: "1", name: 'Pearl Jam', formedIn: 1990 }), 6 Ember.Object.create({ id: "2", name: 'Tool', formedIn: 1991 }), 7 Ember.Object.create({ id: "3", name: 'Long Distance Calling', formedIn: 2003 }), 8 Ember.Object.create({ id: "4", name: 'Led Zeppelin', formedIn: 1970 }) 9 ], 10 (...) 11});
We'll use the id
as the option value and display the name:
On the controller, we collect the id of each selected band, and if we need to display their names, we simply make the mapping between these two:
bands.findBy
is our makeshift store service, which allows us to find an object in a collection by its id. If we used Ember Data, it would become store.findRecord('band', bandId)
or store.peekRecord('band', bandId)
. The only other difference from before is that we set selectedBandIds
instead of selectedBands
in the action handler: