In several spots in my Ember.js applications I have ran into a need for using a select box. Having ran across the chosen select box in the past I wanted a similar experience for my users. This lead me to try and integrate Addepar’s Ember Widgets, but yet it just felt too bulky and I hate the idea that they weren’t completely Ember components. So I attempted to roll my own, and have it so every piece of the select box would be a Ember.js component.
In my attempts to make the component I have an epiphany around customization of components. We should be able to customize without having to mess too much with component. We should never have to extend the component to make the changes required like in the following:
{{select-box
model=model.colors
selections=selectedItems
selectedOptionTemplate='option-view'
optionTemplate='option-view'
prompt='Assignee...'
multiple=true
}}
A component like this allows for defining custom behavior for hover, drag, popover, clicks, and anything else since the display elements for the content would be their own components. With the ability to use components in this manner we can create a set of components with pre-defined core functionality like a grid, table, tree, and many more that anyone can use within their projects while still adding whatever additional functionality is required. Luckily this is all be possible by making use of layout property, by compiling the template at runtime within the init function.
SelectBox = Ember.Component.extend({
...
init: ->
@_super()
optionTemplate = @get('optionTemplate')
selectedOptionTemplate = @get('selectedOptionTemplate')
template = """<div class='ember-select-container input-group '>
<div class="select-choice form-control">
{{#each selections}}
{{#{selectedOptionTemplate} model=this}}
{{else}}
<span class='text-muted'>{{prompt}}</span>
{{/each}}
</div>
<span class="input-group-addon dropdown-toggle" {{action 'toggleDropdown'}}>
<i class="fa fa-caret-square-o-down fa-fw"></i>
</span>
</div>
{{#if showDropdown}}
<div class='dropdown-menu'>
{{input type='text' value=query class='select-search' placeholder='Search for ...' }}
<div class='select-elements'>
{{#each filteredContent}}
<div class='select-item select-element' {{action 'selected' this}} > {{#{optionTemplate} model=this}}</div>
{{else}}
<span>No results match '{{query}}'</span>
{{/each}}
</div>
</div>
{{/if}}
"""
@set('layout', Ember.Handlebars.compile(template))
...
})
Once we have it working, we can do something like this prototype which showcases multiple stylings of the same component.
I’ll probably keep covering this at my blog.