Skip to content

Instantly share code, notes, and snippets.

@eccegordo
Created June 19, 2015 04:13
Show Gist options
  • Save eccegordo/e7c9e8ac03cbbaf3c19b to your computer and use it in GitHub Desktop.
Save eccegordo/e7c9e8ac03cbbaf3c19b to your computer and use it in GitHub Desktop.
custom select component
import Ember from 'ember';
export default Ember.Component.extend({
options: null,
value: null,
prompt: null,
valuePath: null,
labelPath: null,
tagName: 'select',
handleChange: null,
// selection: null,
selectedOption: null,
updateSelectedOptionObserver: Ember.observer('value', 'options.@each', function(){
this.updateSelectedOption();
this.triggerChangeAction();
}),
updateSelectedOption: function(){
var self = this;
var value = this.get('value');
var options = this.get('options');
if (Ember.isBlank(options)){
this.set('selectedOption', null);
return;
}
// Convert to an ember array if not already
if (options.objectAt === undefined){
options = Ember.A(options);
}
// Find the option that matches the value.
for (let i = 0; i < options.get('length'); i++) {
var option = options.objectAt(i);
if (self.valueOfOption(option) == value){ // jshint ignore:line
this.set('selectedOption', option);
return;
}
}// end for
// If the option was not found
this.set('selectedOption', null);
},
triggerChangeAction: function () {
var handleChange = this.get('handleChange');
var value = this.get('value');
var selectedOption = this.get('selectedOption');
if (!Ember.isBlank(handleChange)){
this.sendAction('handleChange', value, selectedOption);
}
},
didRender: function(){
var self = this;
this.$().on('change', function(event){
var selected = Ember.$(event.target).find('option:selected');
var selectedOption = selected.data('optionObject');
self.set('value', self.valueOfOption(selectedOption));
});
this.updateOptions();
this.updateSelectedOption();
},
// Use the value path to get the value for the option passed in.
// if no value path, return the option as the value so the dropdown
// works with POJOs and arrays.
valueOfOption: function (option) {
if (Ember.isBlank(option)){return null;}
var defaultValuePath = 'value';
var valuePath = this.get('valuePath');
var valuePathIsSet = !Ember.isBlank(valuePath);
if (valuePathIsSet && option.get){
return option.get(valuePath);
} else if (!valuePathIsSet && !Ember.isBlank(option.get) && option.get(defaultValuePath) !== undefined){
return option.get(defaultValuePath);
} else if (!valuePathIsSet && option[defaultValuePath] !== undefined){
return option[defaultValuePath];// must be pojo
} else if (valuePathIsSet && option[valuePath] !== undefined){
return option[valuePath];// must be pojo
} else if (option && option.constructor.toString() === 'DS.PromiseObject'){
return option.get('content');
} else {
return option;
}
},
// Use the value path to get the value for the option passed in.
// if no value path, return the option as the value so the dropdown
// works with POJOs and arrays.
labelForOption: function (option) {
if (Ember.isBlank(option)){return '';}
var defaultLabelPath = 'label';
var labelPath = this.get('labelPath');
var labelPathIsSet = !Ember.isBlank(labelPath);
var label;
if (labelPathIsSet && option.get) {
label = option.get(labelPath);
} else if (!labelPathIsSet && option.get && option.get(defaultLabelPath) !== undefined) {
label = option.get(defaultLabelPath);
}else if (!labelPathIsSet && option[defaultLabelPath] !== undefined) {
label = option[defaultLabelPath];
}else if (labelPathIsSet && option[labelPath] !== undefined) {
label = option[labelPath];
}else if (option.label !== undefined) {
label = option.label;
} else {
label = option;
}
return label;
},
showPrompt: Ember.computed('prompt', function(){
return true; //this.get('prompt') !== null;
}),
optionsObserver: Ember.observer('options', 'options.isPending', 'options.@each', 'value', function(){
this.updateOptions();
}),
updateOptions: function(){
var self = this;
var options = this.get('options');
var prompt = this.get('prompt');
var value = this.get('value');
var hasPrompt = !Ember.isBlank(prompt);
var optionTag;
var optionValues;
var didSetSelected = false;
if (this.$() === undefined){return;}// skip if not render yet
if (Ember.isEmpty(options)){return;} // skip if no options
if (options.get && options.get('isPending') === true){return;}
// Conver to an ember array if not already
if (options.objectAt === undefined){
options = Ember.A(options);
}
// DS.PromiseObject is a special case where content null until it resolves
if (value && value.constructor.toString() === 'DS.PromiseObject') {
value = value.get('content');
}
optionValues = options.map(function(o){return self.valueOfOption(o);});
// clear out all options so we don't keep adding new
// ones if the array chagnes.
this.$().find('option').remove();
// Add the prompt if user specified or the selection value is blank.
if(hasPrompt){
optionTag = Ember.$(document.createElement('option'));
optionTag.text(prompt);
self.$().append(optionTag);
}
// Create option tags and set selected=true for the selected one
options.forEach(function(option){
var innerText = self.labelForOption(option);
optionTag = Ember.$(document.createElement('option'));
optionTag.text(innerText);
optionTag.data('optionObject', option);
if (self.valueOfOption(option) == value){// jshint ignore:line
didSetSelected = true;
optionTag.prop('selected', true);
}
self.$().append(optionTag);
});
// If the selection is not in the list of options (ie, the options changed or the value is no longer available)
// set the selected to the first item or nil if there is a prompt.
if (didSetSelected === false && optionValues.indexOf(value) === -1){
if (hasPrompt) {
if (value !== null){
this.set('value', null);
}
} else if (optionValues.length > 0) {
this.set('value', optionValues[0] );
}
}
// // If no options became selected via prior loop
// // and no prompt then select the first option.
if (!hasPrompt && (value === null || value === undefined) && options.get('length') > 0){
this.set('value', optionValues[0] );
}
},//.on('didRender')
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment